<![CDATA[Shahed Nasser]]>https://blog.shahednasser.com/https://blog.shahednasser.com/favicon.pngShahed Nasserhttps://blog.shahednasser.com/Jamify 1.0Wed, 11 Jan 2023 20:37:12 GMT60<![CDATA[How to Create a Python Discord Bot For Data Analysis]]>https://blog.shahednasser.com/how-to-create-a-python-discord-bot-for-data-analysis/Ghost__Post__63bf1a5045c6d805f7d9da8bWed, 11 Jan 2023 20:35:06 GMT

Chatrooms have become very vital for course distribution, gaming, crypto lovers, etc. Discord covers all this by offering dedicated chatrooms for every industry.

But what if you want to create your own discord bot?

In this article, we are going to create our own bot using Python.

What is Discord?

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.

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.

What is a bot?

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.

Why Use Python to Create Discord Bot?

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 web scraping, designing desktop applications, and games, and many more.

With endless possibilities and applications, Python would be a go to language for creating a discord bot.

Other reasons why you might choose to use Python for creating a Discord bot:

  1. Python is a popular, 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.
  2. Python is easy to learn and use. Its syntax is straightforward and readable, so it's a good language to start with if you're new to programming.
  3. Python has strong support 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.
  4. Python is fast to prototype and develop with. Its simplicity and flexibility make it a great choice for rapid development, so you can build and deploy your Discord bot quickly.

How to create a Discord bot using Python?

Using the Discord Python library, you can easily create a bot that can perform a variety of tasks, such as sending messages, moderating conversations, and more.

You can customize your bot to perform data analysis tasks by using various Python libraries, such as NumPy, Pandas, and Matplotlib.

Prerequisites

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.

You can then use the Discord Python library and the discord.py module to interact with the Discord API and create your bot.

Installation

I am assuming you have already installed Python on your machine. Then, install the Discord Python library, called discord.py, using pip.

pip install discord.py

After this create your python file where you will write the code and import all the libraries.

import discord
from discord.ext import commands

Then we have to create a new Discord client and assign it to a variable.

client = commands.Bot(command_prefix = '.')

Then define a function that will be called when the bot is ready to go online.

@client.event
async def on_ready():
print('Bot is ready!')

The next step is to use the @client.command() decorator to define a function that will be called when a certain command is received.

@client.command()
async def greet(ctx):
await ctx.send('Hello!')

Finally, run the bot using the run() method, passing in your Discord bot's token.

client.run('YOUR_BOT_TOKEN_HERE')

This is just a basic outline of how you can create a Discord bot in Python.

How to interact with discord APIs using python?

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:

  1. discord.py: 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.
  2. discord.py-rewrite: This is a rewrite of discord.py that uses a more modern syntax and includes additional features such as support for WebSockets.

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.

Here is an example of how you might use the discord.py library to send a message to a Discord channel.

import discord

client = discord.Client()

@client.event
async def on_ready():
   print('Logged in as')
   print(client.user.name)
   print(client.user.id)
   print('------')

@client.event
async def on_message(message):
   if message.content.startswith('!hello'):
       await message.channel.send('Hello!')

client.run('your_bot_token')

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 your_bot_token with the actual token for your bot, which you can get from the Discord Developer Portal.

Getting data for the bot for data analysis

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.

import discord
import requests
import pandas as pd

client = discord.Client()

@client.event
async def on_message(message):
   if message.content.startswith('!data'):
       # Retrieve data from API
       data = requests.get('https://api.example.com/data').json()
      
       # Convert data to a Pandas DataFrame
       df = pd.DataFrame(data)
      
       # Perform some basic analysis on the data
       mean = df['value'].mean()
       median = df['value'].median()
       std = df['value'].std()
      
       # Send results back to Discord
       await message.channel.send(f'Mean: {mean:.2f}')
       await message.channel.send(f'Median: {median:.2f}')
       await message.channel.send(f'Standard Deviation: {std:.2f}')

client.run('your_bot_token')

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 https://api.example.com/data with the actual URL of the API you want to use and your_bot_token with the actual token for your bot.

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.

Conclusion

In this tutorial, you learned how to create a Discord bot using Python and the discord.py library. 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.

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.

]]>
<![CDATA[How to Lint Code and Prose in Documentation]]>https://blog.shahednasser.com/how-to-lint-code-and-prose-in-documentation/Ghost__Post__63af16954e918d05f3537d41Fri, 30 Dec 2022 17:48:59 GMT

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.

This includes both the written content and the code blocks. Your documentation should follow a style guide that keeps your content across pages consistent.

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.

This article covers the different methods and ways you can lint prose or content and code blocks to ensure it follows your style guide.

Why Use a Style Guide?

Documentation should provide a great developer experience. This includes consistency, clarity, and technical accuracy.

Creating a style guide can provide your documentation with the following benefits:

  • 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.
  • 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.
  • You maintain content that is written for everyone. Your tone shouldn't be biased toward gender, development level, disabilities, or anything similar.

Although style guides generally refer to the content of the documentation, you should also maintain a set of rules for your code block.

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.

Markdown Content

Most documentation is written in Markdown (MD) or MDX formats. So, this article specifically targets linting markdown files.

If you write your documentation in different file formats, these solutions might not work for you.

Lint Prose with Vale

How to Lint Code and Prose in Documentation

Vale 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.

So many projects and companies use Vale, including GitHub, Microsoft, Angular, and more.

Vale provides some ready-made styles and packages that you can immediately add to your configurations. For example, you can use Microsoft's style guide.

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 Joblint styles.

Vale is easy to set up and use. You can then either choose from existing styles or create your own. Vale also provides a config generator to save you time.

Then, you can test your content by simply running a command like this:

vale README.md

Vale also has a VS Code extension that allows you to quickly catch errors and warnings in your editor.

Not only can you use Vale through the command line, but you can also integrate Vale into your development or release pipeline.

For example, Vale provides a GitHub Action 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.

Lint Code with ESLint

ESLint 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.

There are plugins that allow running ESLint with other languages. For example, typescript-eslint allows linting TypeScript.

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.

To do that with ESLint, you'll need to use the eslint-plugin-markdown. This plugin allows you to lint JavaScript, TypeScript, and other languages within your documentation files.

You can then define the rules similar to how you would with ESLint.

You can install the plugin in your Node.js project with the following command:

npm install --save-dev eslint eslint-plugin-markdown

Then, create the file .eslintrc.js in the root directory with the following content:

module.exports = {
    extends: "plugin:markdown/recommended",
    plugins: ["markdown"],
    overrides: [
        {
            files: ["**/*.md"],
            processor: "markdown/markdown"
        },
    ]
};

This enables running the linter on Markdown files. You can also add **/*.mdx to the files array to run the linter on MDX files as well.

You can specify which languages you want to lint in the overrides array. For example:

overrides: [
    //...
    {
    	files: ["**/*.md/*.js"],
        // optional
        rules: {
			// ...
        }
    }
]

All languages are nested under **/*.md. So, to specify JavaScript files, you pass the pattern **/*.md/*.js.

You can also optionally pass rules specific to that language under the rules property.

Then, you can run the eslint command to test the code blocks in your documentation:

eslint

This assumes that you created the configuration file at the root of your project. Otherwise, you need to pass the CLI tool some options.

You can also pass it the --fix option to immediately fix errors that can be fixed:

eslint --fix

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.

Conclusion

This article lists two tools that can be used for configuring and automating linters both for the prose and the code of your documentation.

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.

]]>
<![CDATA[How to Get Elements From the DOM Using JavaScript]]>https://blog.shahednasser.com/how-to-get-elements-from-the-dom-using-javascript/Ghost__Post__631f8eea4e918d05f3537b51Mon, 19 Sep 2022 10:58:26 GMT

While creating a website and working with JavaScript, you'll often need to get access to elements in the DOM for different purposes.

This tutorial shows you different ways to get an element from the DOM using JavaScript.

getElementById

The getElementById() method allows you to retrieve an element from the DOM using the element's ID.

If no element exists in the DOM with the supplied ID, null will be returned instead.

For example:

const mainElement = document.getElementById('main');

getElementsByTagName

The getElementsByTagName() allows you to retrieve an HTMLCollection of elements that have the tag name you supply to the method. An example of a tag name is div.

Items in an HTMLCollection can be accessed similarly to how you would access items in an array.

For example:

const divElements = document.getElementsByTagName('div');
console.log(divElements[0]);

You can use this method on any element and not just the document. That way, you can retrieve all children of that element that have the supplied tag name.

For example:

const divElements = document.getElementsByTagName('div');
const pElements = divElements[0].getElementsByTagName('p');
console.log(pElements);

getElementsByClassName()

The getElementsByClassName() method allows you to retrieve a live HTMLCollection of elements that have the class name you provide as a parameter.

A live HTMLCollection 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.

For example:

const mainElements = document.getElementsByClassName('main');
console.log(mainElements);

getElementsByName()

The getElementsByName() method allows you to retrieve elements by the value of the name attribute. For example, you can use it to retrieve input elements that have the name attribute set to email.

This method returns a live NodeList, which is generally similar to an HTMLCollection, but the items in the list can be accessed through the methods it provides.

For example:

const emailElements = document.getElementsByName('email');
console.log(emailElements.item(0));

querySelector

The querySelector() method allows you to retrieve the first element that matches the specified selector. The selector can be any CSS selector.

For example:

const elm = document.querySelector('.main > p');
console.log(elm);

This method can be used on any element, and not just the document. So, you can use it to retrieve a child element of a parent element that matches the specified selector.

For example:

const table = document.querySelector('.main > table');
const thead = table.querySelector('thead');

querySelectorAll

The querySelectorAll() method allows you to retrieve all elements that match the specified selector. This method returns a NodeList.

For example:

const elms = document.querySelectorAll('.main > p');
console.log(elms.item(0));

This method can be used on any element, and not just the document. So, you can use it to retrieve all child elements of a parent element that match the specified selector.

For example:

const table = document.querySelector('.main > table');
const rows = table.querySelectorAll('tr');
for (const row of rows) {
    console.log(row);
}

children

The children property allows you to retrieve all immediate child elements of the document or any element. This property's type is a live HTMLCollection.

For example:

const rows = document.querySelectorAll('table tr');
for (const row of rows) {
    console.log(row.children);
}

firstElementChild

The firstElementChild property allows you to retrieve the first child element of the document or any element.

If the element does not have children, the value of firstElementChild is null.

For example:

const rows = document.querySelectorAll('table tr');
for (const row of rows) {
    console.log(row.firstElementChild);
}

lastElementChild

The lastElementChild property allows you to retrieve the last child element of the document or any element.

If the element does not have children, the value of lastElementChild is null:

const rows = document.querySelectorAll('table tr');
for (const row of rows) {
    console.log(row.lastElementChild);
}

scripts

The scripts property allows you to retrieve all <script> elements in the document. It returns an HTMLCollection of elements.

For example:

console.log(document.scripts);

elementFromPoint

The elementFromPoint() 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.

For example:

const elm = document.elemetFromPoint(100, 20);
console.log(elm);

elementsFromPoint

The elementsFromPoint() method allows you to retrieve an array of Elements starting from a specified point until the end of the viewport.

For example:

const elms = document.elementsFromPoint(100, 20);
console.log(elm[0]);

closest

The closest() method available on elements (not on the document) 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 null.

For example:

const closestElm = table.closest('div');
console.log(closestElm);

nextElementSibling

The nextElementSibling property on elements (not on the document) allows you to retrieve the element that follows the current element among its parent's child elements.

If there are no elements after this element, the value of the property will be null.

For example:

console.log(table.nextElementSibling);

previousElementSibling

The previousElementSibling property on elements (not on the document) allows you to retrieve the element that proceeds the current element among its parent's child elements.

If there are no elements before this element, the value of the property will be null.

For example:

console.log(table.previousElementSibling);

Conclusion

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.

]]>
<![CDATA[Hacktoberfest 2022: Everything You Need to Know to Participate]]>https://blog.shahednasser.com/hacktoberfest-2022-everything-you-need-to-know-to-participate/Ghost__Post__6320b1324e918d05f3537c2bTue, 13 Sep 2022 17:11:43 GMT

Hacktoberfest is an annual event that occurs in October. It is created by DigitalOcean. Thousands of developers participate in this event across the globe.

This article explains what Hacktoberfest is, how you can participate, and more!

What is Hacktoberfest?

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.

Who Can Participate in Hacktoberfest?

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.

There are two ways to participate in Hacktoberfest: as a contributor or as a maintainer.

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.

New in Hacktoberfest 2022

Hacktoberfest 2022 encourages low-code and non-code contributions, which can be done through blog posts, translating content, graphic design, and more. The contributions must be tracked through GitHub Pull Requests (PRs) as other types of contributions.

How to Participate in Hacktoberfest 2022?

Registration to Hacktoberfest

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.

Participating as a Contributor

As a contributor, during October you must have four PRs that either:

  • Are merged into a participating repository;
  • Or have the hacktoberfest-accepted label;
  • Or have an approving review, but not closed or draft.

A participating repository is a repository that has the hacktoberfest topic. Participation can be done through GitHub or GitLab.

Participating as a Maintainer

To participate as a maintainer, you must facilitate participation for contributors. The first step is to either:

  1. Add the hacktoberfest topic to your repository;
  2. Or add the hacktoberfest-accepted label into your repository to be used on pull requests.

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 hacktoberfest-accepted label into these PRs.

Rules

  1. For PRs to be counted into your participation in Hacktoberfest, they must be merged between October 1st and October 31st.
  2. Contributions must be made to public repositories.
  3. If a PR has a label that contains the word spam in it, the PR will not be counted. Also, if a participant has 2 or more spam PRs, they'll be disqualified from Hacktoberfest.
  4. If a PR has a label that contains the word invalid, it will not be counted. The exception for this is if the PR also has the label hacktoberfest-accepted.

Unwritten Rules

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.

For Contributors

  1. Do not spam any maintainer: 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.
  2. Make valuable contributions: 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.
  3. Give back to your favorite projects: 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.
  4. Follow rules set by each project: Projects should have contributing guidelines that explain how you can contribute to them. Make sure you read those first before you contribute.

For Maintainers

  1. Create contributing guidelines: 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.
  2. Welcome all developers: 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.

Additional Resources

If you're interested in learning more about Hacktoberfest and how to contribute, here are some resources that can be helpful:

  1. Hacktoberfest's participation page.
  2. For contributors: Tips for Beginners to Open Source Projects.
  3. For maintainers: Tips for Beginner Maintainers of Open Source Projects.
  4. Awesome for Beginners list.
]]>
<![CDATA[How to Become a Technical Writer?]]>https://blog.shahednasser.com/how-to-become-a-technical-writer/Ghost__Post__631d038c4e918d05f3537a81Mon, 12 Sep 2022 15:43:39 GMT

This year I transitioned from a full-stack developer to a technical writer. 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.

This article explains briefly what technical writing is, and how you can become a technical writer.

What is Technical Writing?

Technical writing is the practice of writing down an explanation of how something technical works or can be used.

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.

Skills you Need to Become a Technical Writer

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.

Technical Skills

It's important that before you become a technical writer, you take the time to build your experience as an engineer.

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.

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.

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.

Writing Skills

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.

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.

Writing Technical Content for Blogs

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.

Own Blog

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.

It also helps you find more freelance opportunities as a technical writer for other websites. It acts as a live resume.

Creating your own blog can seem like a big, difficult task, but that's actually not true.

One way to create your own blog is using platforms like Hashnode or Medium. It is for free and you don't need to manage your blog or the hosting, as that is done for you.

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 Ghost CMS, Strapi, WordPress, and more.

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.

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.

The more you write, the more you'll be practicing while also sharing your knowledge with other developers.

Other Websites and Blogs

Many websites pay technical writers to write content for them. This includes websites like SitePoint, Draft.dev, LogRocket, and more.

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.

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.

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.

Writing Documentation

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.

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.

Documentation is similar to blog posts, except they usually delve more into the deeper topic and they are related to one piece of software.

You can learn about different good practices of writing documentation by observing well-written documentation such as Stripe's documentation.

I personally have learned a lot from reading Docs for Developers, which is a book that explains the process of writing documentation from start to end in a very easy-to-understand language.

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.

Conclusion

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.

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.

]]>
<![CDATA[What are Events in JavaScript and How to Handle Them?]]>https://blog.shahednasser.com/what-are-events-in-javascript-and-how-to-handle-them/Ghost__Post__62f3f8304e918d05f3537963Wed, 10 Aug 2022 19:49:03 GMT

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.

This article helps beginners understand what Events are in JavaScript and how to handle them.

Why Use Events

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.

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.

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.

Add Event Handler

To listen to events, you can use the addEventListener method. This method is available on every Element and Node in the document.

addEventListener 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 options for the listener.

In most cases, you only need to use the first two parameters. Here's an example of handling the click event on a button:

const button = document.querySelector("button");
button.addEventListener("click", function (e) {
    alert("Button clicked");
});

This retrieves the first button on the page and, when the button is clicked, shows an alert.

What are Events in JavaScript and How to Handle Them?

Can an Event Have More Than One Handler?

The same event can have many handlers. The handlers are triggered one by one when the event occurs.

Event Object

As you can see, the function passed as a second parameter to addEventListener received the argument e. This is an Event object. This object may have different properties depending on its underlying type. However, it has some common important properties.

A frequently used property on the Event object is the target 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.

For example:

document.querySelector("input").addEventListener("change", function (e) {
    alert(e.target.value);
});

This code snippet adds an event handler to the first input element on the change event. The change 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).

When the change event occurs and the handler is triggered, the value of the input is retrieved using e.target.value and used in an alert.

Prevent Default Behavior of the Event

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.

To prevent the default behavior of an event, you can use the preventDefault() method on the Event object.

For example:

const a = document.querySelector("a.some-link");
a.addEventListener("click", function (e) {
    e.preventDefault();
    if(confirm("Are you sure?")) {
      window.location.href = e.target.href;
    }
});

This adds an event handler to the click events on a link that has the class some-link. In the event handler, e.preventDefault() is used to prevent the default behavior of opening the page indicated in the href attribute.

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.

Prevent Other Handlers from Handling this Event

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.

There are two methods that can be used to prevent other handlers from handling the same event: stopPropagation and stopImmediatePropagation.

stopPropagation is used to prevent other event handlers from handling an event during the bubbling phase.

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.

In this case, stopPropagation 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.

To prevent the event from being handled by subsequent handlers, you can use stopImmediatePropagation.

For example:

const button = document.querySelector("button");

button.addEventListener("click", function (e) {
  e.stopImmediatePropagation();
  alert("Hello!");
});

button.addEventListener("click", function (e) {
  alert("Bye!")
})

Although the button has two event handlers that listen to the click event, only the first one will run since it calls the stopImmediatePropagation function.

Difference Between preventDefault, stopPropagation, and stopImmediatePropagation

preventDefault only prevents the default behavior of the event. However, it does not prevent other handlers from handling the event.

stopPropagation and stopImmediatePropagation only prevent other handlers from handling the event. However, they don't prevent the default behavior of the event.

If you want to prevent both the default behavior and other handlers from handling the event, use preventDefault with either stopPropagation or stopImmediatePropagation.

Handle Events on Dynamic Elements

Consider the following example:

const buttons = document.querySelectorAll(".btn");

buttons.forEach((btn) => {
  btn.addEventListener("click", function (e) {
    alert("Hello!");
  });
})

//create new button
const button = document.createElement('button');
button.classList.add('btn');
button.textContent = "Bye";
document.body.append(button);

In this example, you first retrieve all buttons that have the class btn. Then, you loop over these buttons and add an event listener that just shows the alert "Hello" when the button is clicked.

Then, you dynamically create a new button, add the class btn to that button, and add it to the body of the document.

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.

This is because the element was not part of the elements retrieved using querySelectorAll as it didn't exist at the time.

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.

In that case, instead of adding the event handler directly to each element separately, you can add the event handler to the document's body and use e.target to check if the element triggered matches a specific condition.

For example, you can transform the previous example to the following:

document.body.addEventListener("click", function (e) {
  if (e.target.classList.contains("btn")) {
    alert("Hello!");
  }
})

//create new button
const button = document.createElement('button');
button.classList.add('btn');
button.textContent = "Bye";
document.body.append(button);

You add a handler to the click event on the body. In the handler, you check if e.target has the class btn and only perform the necessary action if it does.

Now, when any of the elements that have the class btn, whether dynamically or initially created, are clicked, the event handler will run for them.

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.

Remove Event Handler

In some cases, you might want to remove an event handler for an element. To do that, you can use the removeEventListener method. This method is available on every Element and Node in the document.

This method receives the same parameters addEventListener receives. It's important to pass the same function that you passed to addEventListener. For that reason, people commonly define the function separately, then pass it to addEventListener and removeEventListener.

For example:

const button = document.querySelector("button");

function handleClick (e) {
  alert("Hello");
}

button.addEventListener("click", handleClick);

//some time later
button.removeEventListener("click", handleClick);

Conclusion

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:

  1. Introduction to Events
  2. Event Reference
]]>
<![CDATA[React (TanStack) Query Tutorial for Beginners]]>https://blog.shahednasser.com/react-query-tutorial-for-beginners/Ghost__Post__62dd14674e918d05f353777dSun, 24 Jul 2022 15:50:35 GMT

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.

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.

Please note that this version uses v4 of React Query which is now named TanStack Query.

You can find the code for this tutorial in this GitHub repository.

Prerequisites

Before starting with this tutorial make sure you have Node.js installed. You need at least version 14.

Server Setup

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.

If you already have a server you can skip this section and go to the Website Setup section.

Create Server Project

Create a new directory called server then initialize a new project using NPM:

mkdir server
cd server
npm init -y

Install Dependencies

Then, install the packages you'll need for the development of the server:

npm i express cors body-parser sqlite3 nodemon

Here's what each of the packages is for:

  1. express to create a server using Express.
  2. cors is an Express middleware used to handle CORS on your server.
  3. body-parser is an Express middleware used to parse the body of a request.
  4. sqlite3 is an SQLite database adapter for Node.js.
  5. nodemon is a library used to restart the server whenever new changes occur to the files.

Create Server

Create the file index.js with the following content:

const express = require('express');

const app = express();
const port = 3001;
const cors = require('cors');
const sqlite3 = require('sqlite3').verbose();
const bodyParser = require('body-parser');

app.use(bodyParser.json());
app.use(cors());

app.listen(port, () => {
  console.log(`Notes app listening on port ${port}`);
});

This initializes the server using Express on port 3001. It also uses the cors and body-parser middleware.

Then, in package.json add a new script start to run the server:

  "scripts": {
    "start": "nodemon index.js"
  },

Initialize the Database

In index.js before app.listen add the following code:

const db = new sqlite3.Database('data.db', (err) => {
  if (err) {
    throw err;
  }

  // create tables if they don't exist
  db.serialize(() => {
    db.run(`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)`);
  });
});

This creates a new database if it doesn't exist in the file data.db. Then, if the notes table doesn't exist on the database it creates it as well.

Add Endpoints

Following the database code, add the following code to add the endpoints:

app.get('/notes', (req, res) => {
  db.all('SELECT * FROM notes', (err, rows) => {
    if (err) {
      console.error(err);
      return res.status(500).json({ success: false, message: 'An error occurred, please try again later' });
    }

    return res.json({ success: true, data: rows });
  });
});

app.get('/notes/:id', (req, res) => {
  db.get('SELECT * FROM notes WHERE id = ?', req.params.id, (err, row) => {
    if (err) {
      console.error(err);
      return res.status(500).json({ success: false, message: 'An error occurred, please try again later' });
    }

    if (!row) {
      return res.status(404).json({ success: false, message: 'Note does not exist' });
    }

    return res.json({ success: true, data: row });
  });
});

app.post('/notes', (req, res) => {
  const { title, content } = req.body;

  if (!title || !content) {
    return res.status(400).json({ success: false, message: 'title and content are required' });
  }

  db.run('INSERT INTO notes (title, content) VALUES (?, ?)', [title, content], function (err) {
    if (err) {
      console.error(err);
      return res.status(500).json({ success: false, message: 'An error occurred, please try again later' });
    }

    return res.json({
      success: true,
      data: {
        id: this.lastID,
        title,
        content,
      },
    });
  });
});

app.delete('/notes/:id', (req, res) => {
  const { id } = req.params;

  db.get('SELECT * FROM notes WHERE id = ?', [id], (err, row) => {
    if (err) {
      console.error(err);
      return res.status(500).json({ success: false, message: 'An error occurred, please try again later' });
    }

    if (!row) {
      return res.status(404).json({ success: false, message: 'Note does not exist' });
    }

    db.run('DELETE FROM notes WHERE id = ?', [id], (error) => {
      if (error) {
        console.error(error);
        return res.status(500).json({ success: false, message: 'An error occurred, please try again later' });
      }

      return res.json({ success: true, message: 'Note deleted successfully' });
    });
  });
});

Briefly, this creates 4 endpoints:

  1. /notes endpoint of the method GET to fetch all notes.
  2. /notes/:id endpoint of the method GET to fetch a note by an ID.
  3. /notes endpoint of the method POST to add a note.
  4. /notes/:id endpoint of the method DELETE to delete a note.

Test Server

Run the following command to start the server:

npm start

This starts the server on port 3001. You can test it out by sending a request to localhost:3001/notes.

Website Setup

In this section, you'll create the website with Create React App (CRA). This is where you'll make use of React Query.

Create Website Project

To create a new React app, run the following command in a different directory:

npx create-react-app website

This creates a new React app in the directory website.

Install Dependencies

Run the following command to change to the website directory and install the necessary dependencies for the website:

cd website
npm i @tanstack/react-query tailwindcss postcss autoprefixer @tailwindcss/typography @heroicons/react @windmill/react-ui

The @tanstack/react-query library is the React Query library which is now named TanStack Query. The other libraries are Tailwind CSS related libraries to add styling to the website.

Tailwind CSS Setup

This section is optional and is only used to set up Tailwind CSS.

Create the file postcss.config.js with the following content:

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

Also, create the file tailwind.config.js with the following content:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [
    require('@tailwindcss/typography')
  ],
}

Then, create the file src/index.css with the following content:

@tailwind base;
@tailwind components;
@tailwind utilities;

Finally, in index.js import src/index.css at the beginning of the file:

import './index.css';

Use QueryClientProvider

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 src/index.js which wraps up your entire website's components.

In src/index.js add the following imports at the beginning of the file:

import {
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'

Then, initialize a new Query client:

const queryClient = new QueryClient()

Finally, change the parameter passed to root.render:

root.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>
);

This wraps the App component which holds the rest of the website's components with QueryClientProvider. This provider accepts the prop client which is an instance of QueryClient.

Now, all components within the website will have access to the Query Client which is used to fetch, cache, and manipulate the server data.

Implement Display Notes

Fetching data from the server is an act of performing a query. Therefore, you'll use useQuery in this section.

You'll display notes in the App component. These notes are fetched from the server using the /notes endpoint.

Replace the content of app.js with the following content:

import { PlusIcon, RefreshIcon } from '@heroicons/react/solid'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'

function App() {
  const { isLoading, isError, data, error } = useQuery(['notes'], fetchNotes)

  function fetchNotes () {
    return fetch('http://localhost:3001/notes')
    .then((response) => response.json())
    .then(({ success, data }) => {
      if (!success) {
        throw new Error ('An error occurred while fetching notes');
      }
      return data;
    })
  }

  return (
    <div className="w-screen h-screen overflow-x-hidden bg-red-400 flex flex-col justify-center items-center">
      <div className='bg-white w-full md:w-1/2 p-5 text-center rounded shadow-md text-gray-800 prose'>
        <h1>Notes</h1>
        {isLoading && <RefreshIcon className="w-10 h-10 animate-spin mx-auto"></RefreshIcon>}
        {isError && <span className='text-red'>{error.message ? error.message : error}</span>}
        {!isLoading && !isError && data && !data.length && <span className='text-red-400'>You have no notes</span>}
        {data && data.length > 0 && data.map((note, index) => (
          <div key={note.id} className={`text-left ${index !== data.length - 1 ? 'border-b pb-2' : ''}`}>
            <h2>{note.title}</h2>
            <p>{note.content}</p>
            <span>
              <button className='link text-gray-400'>Delete</button>
            </span>
          </div>
        ))}
      </div>
      <button className="mt-2 bg-gray-700 hover:bg-gray-600 rounded-full text-white p-3">
        <PlusIcon className='w-5 h-5'></PlusIcon>
      </button>
    </div>
  );
}

export default App;

Here's briefly what's going on in this code snippet:

  1. You use useQuery 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 fetchNotes function.
  2. useQuery returns an object that holds many variables. Here, you use 4 of them: isLoading is a boolean value that determines whether the data is currently being fetched; isError is a boolean value that determines if an error occurred. data is the data that is fetched from the server; and error is the error message if isError is true.
  3. The fetchNotes function must return a promise that either resolves data or throws an error. In the function, you send a GET request to localhost:3001/notes to fetch the notes. If the data is fetched successfully it is returned in the then fulfillment function.
  4. In the returned JSX, if isLoading is true, a loading icon is shown. If isError is true, an error message is shown. If data is fetched successfully and has any data in it, the notes are rendered.
  5. You also show a button with a plus icon to add new notes. You'll implement this later.

Test Displaying Notes

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:

npm start

This runs your React app on localhost:3000 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.

React (TanStack) Query Tutorial for Beginners

Implement Add Notes Functionality

Adding a note is an act of mutation on the server data. Therefore, you'll be using the useMutation hook in this section.

You'll create a separate component that shows the form used to add a note.

Create the file src/form.js with the following content:

import { useMutation, useQueryClient } from '@tanstack/react-query'

import { useState } from 'react'

export default function Form ({ isOpen, setIsOpen }) {
  const [title, setTitle] = useState("")
  const [content, setContent] = useState("")
  const queryClient = useQueryClient()

  const mutation = useMutation(insertNote, {
    onSuccess: () => {
      setTitle("")
      setContent("")
    }
  })

  function closeForm (e) {
    e.preventDefault()
    setIsOpen(false)
  }

  function insertNote () {
    return fetch(`http://localhost:3001/notes`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        title,
        content
      })
    })
    .then((response) => response.json())
    .then(({ success, data }) => {
      if (!success) {
        throw new Error("An error occured")
      }
      
      setIsOpen(false)
      queryClient.setQueriesData('notes', (old) => [...old, data])
    })
  }

  function handleSubmit (e) {
    e.preventDefault()
    mutation.mutate()
  }

  return (
    <div className={`absolute w-full h-full top-0 left-0 z-50 flex justify-center items-center ${!isOpen ? 'hidden' : ''}`}>
      <div className='bg-black opacity-50 absolute w-full h-full top-0 left-0'></div>
      <form className='bg-white w-full md:w-1/2 p-5 rounded shadow-md text-gray-800 prose relative' 
        onSubmit={handleSubmit}>
        <h2 className='text-center'>Add Note</h2>
        {mutation.isError && <span className='block mb-2 text-red-400'>{mutation.error.message ? mutation.error.message : mutation.error}</span>}
        <input type="text" placeholder='Title' className='rounded-sm w-full border px-2' 
          value={title} onChange={(e) => setTitle(e.target.value)} />
        <textarea onChange={(e) => setContent(e.target.value)} 
          className="rounded-sm w-full border px-2 mt-2" placeholder='Content' value={content}></textarea>
        <div>
          <button type="submit" className='mt-2 bg-red-400 hover:bg-red-600 text-white p-3 rounded mr-2 disabled:pointer-events-none' 
            disabled={mutation.isLoading}>
            Add</button>
          <button className='mt-2 bg-gray-700 hover:bg-gray-600 text-white p-3 rounded'
            onClick={closeForm}>Cancel</button>
        </div>
      </form>
    </div>
  )
}

Here's a brief explanation of this form

  1. This form acts as a pop-up. It accepts isOpen and setIsOpen props to determine when the form is opened and handle closing it.
  2. You use useQueryClient to get access to the Query Client. This is necessary to perform a mutation.
  3. To handle adding a note on your server and keep all data in your query client synced, you must the useMutation hook.
  4. The useMutation hook accepts 2 parameters. Thie first one is the function that will handle the mutation, which in this case is insertNote. The second parameter is an object of options. You pass it one option onSuccess which is a function that runs if the mutation is performed successfully. You use this to reset the title and content fields of the form.
  5. In insertNote, you send a POST request to localhost:3001/notes and pass in the body the title and content of the note to be created. If the success body parameter returned from the server is false, an error is thrown to signal that the mutation failed.
  6. If the note is added successfully, you change the cached value of the notes key using the queryClient.setQueriesData 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.
  7. In this component you display a form with 2 fields: title and content. In the form, you check if an error occurs using mutation.isError and get access to the error using mutation.error.
  8. You handle form submission in the handleSubmit function. Here, you trigger the mutation using mutation.mutate. This is where the insertNote function is triggered to add a new note.

Then, in src/app.js add the following imports at the beginning of the file:

import Form from './form'
import { useState } from 'react'

Then, at the beginning of the component add a new state variable to manage wheter the form is opened or not:

const [isOpen, setIsOpen] = useState(false)

Next, add a new function addNote that just uses setIsOpen to open the form:

function addNote () {
    setIsOpen(true)
}

Finally, in the returned JSX, replace the button with the plus icon with the following:

<button className="mt-2 bg-gray-700 hover:bg-gray-600 rounded-full text-white p-3" onClick={addNote}>
    <PlusIcon className='w-5 h-5'></PlusIcon>
</button>
<Form isOpen={isOpen} setIsOpen={setIsOpen} />

This sets the onClick handler of the button to addNote. It also adds the Form component you created earlier as a child component of App.

Test Adding a Note

Rerun your server and React app if they're not running. Then, open the website again at localhost:3000. Click on the plus button and a pop up will open with the form to add a new note.

React (TanStack) Query Tutorial for Beginners

Enter a random title and content then click Add. The pop up form will then close and you can see the new note added.

React (TanStack) Query Tutorial for Beginners

Implement Delete Note Functionality

The last functionality you'll add is deleting notes. Deleting a note is another act of mutation as it manipulates the server's data.

At the beginning of the App component in src/app.js add the following code:

const queryClient = useQueryClient()
const mutation = useMutation(deleteNote, {
    onSuccess: () => queryClient.invalidateQueries('notes')
})

Here, you get access to the query client using useQueryClient. Then, you create a new mutation using useMutation. You pass it the function deleteNote (which you'll create next) as a first parameter and an object of options.

To the onSuccess option you pass a function that does one thing. It executes the method queryClient.invalidateQueries. This method marks the cached data for a specific key as outdated, which triggers retrieving the data again.

So, once a note is deleted, the query you created earlier that executes the function fetchNotes will be triggered and the notes will be fetched again. If you had created other queries on your website that use the same key notes, they'll also be triggered to update their data.

Next, add the function deleteNote in the App component in the same file:

function deleteNote (note) {
    return fetch(`http://localhost:3001/notes/${note.id}`, {
      method: 'DELETE'
    })
    .then((response) => response.json())
    .then(({ success, message }) => {
      if (!success) {
        throw new Error(message);
      }

      alert(message);
    })
  }

This function receives the note to be deleted as a parameter. It sends a DELETE request to localhost:3001/notes/:id. If the success body parameter of the response is false, an error is thrown. Otherwise, only an alert is shown.

Then, in the returned JSX of the App component, change how the loading icon and error where shown previously to the following:

{(isLoading || mutation.isLoading) && <RefreshIcon className="w-10 h-10 animate-spin mx-auto"></RefreshIcon>}
{(isError || mutation.isError) && <span className='text-red'>{error ? (error.message ? error.message : error) : mutation.error.message}</span>}

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.

Finally, find the delete button of a note and add an onClick handler:

<button className='link text-gray-400' onClick={() => mutation.mutate(note)}>Delete</button>

On click, the mutation responsible for deleting the note is triggered using mutation.mutate. You pass it the note to delete which is the current note in a map loop.

Test Deleting a Note

Rerun your server and React app if they're not running. Then, open the website again at localhost:3000. Click the Delete link for any of your notes. If the note is deleted successfully, an alert will be shown.

React (TanStack) Query Tutorial for Beginners

After closing the alert, the notes will be fetched again and displayed, if there are any other notes.

React (TanStack) Query Tutorial for Beginners

Conclusion

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.

Make sure to check out the official documentation to learn more about what you can do with React Query.

]]>
<![CDATA[Beginner's Guide to Kubernetes: Understand the Basics]]>https://blog.shahednasser.com/beginners-guide-to-kubernetes-understand-the-basics/Ghost__Post__62d068d44e918d05f353772cThu, 14 Jul 2022 19:14:54 GMT

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.

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.

What is Kubernetes?

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.

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.

I get it, if you were to ask what container orchestration is, Let’s see in short what that means,

Moving your Application to the Internet

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.

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.

Virtual Machines

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.

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.

If you have higher resources, it can accommodate a lot of users and less if it has lesser resources.

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.

Also, it is a tedious task to create, monitor, and manage multiple instances of the same and redirect them if one is busy.

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.

Containers

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.

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.

Container Orchestration tool

Kubernetes is a container orchestration tool, which means you get to increase, decrease, destroy, create, and configure containers with higher specifications and much more.

These help in scalability, monitoring, Health-checks and many more. Let’s see a real-time example of how container orchestration helps.

Short overview of a Real-time application

You developed a full-stack application. It will probably have a Front-end facing application, a backend, and a database.

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.

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.

Containerizing the applications

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.

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.

Pushing the container images

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.

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.

Now that the image is pushed to Kubernetes, the image will be built and the container will run.

Now zooming out, let’s know some terms and structure of Kubernetes.

Structure of Kubernetes and its terms

What are Pods and Nodes in Kubernetes?

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.

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.

The order is like this: container < pod < node < cluster.

We can start the pod by mentioning how many replicas we want, how many maximum replicas it can have, auto-scaling, health-check, etc.

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.

What is downtime?

It is the time duration, in which the server is neither accessible nor working.

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.

To prevent this and enhance the user experience, Zero downtime is a requirement nowadays.

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…

Who needs Kubernetes?

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.

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.

Conclusion

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.

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.

For a large-scale application, Kubernetes saves a lot of time and automates almost everything related to scaling and everything with zero downtime.

]]>
<![CDATA[How to Create and Deploy a Documentation Website With Docusaurus and Netlify]]>https://blog.shahednasser.com/how-to-create-and-deploy-a-documentation-website-with-docusaurus-and-netlify/Ghost__Post__627f9c2839840e1ac2875259Mon, 16 May 2022 10:29:16 GMT

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.

In this tutorial, you'll learn how to create documentation with Docusaurus. This documentation website will have features such as multi-language code blocks and local search. You'll then deploy the website with Netlify.

Prerequisites

Docusaurus requires Node.js version 14.3 or above. If you don't have Node.js installed you can install it from their website.

To deploy your docusaurus website, you'll need a GitHub and Netlify accounts. You must also have an empty repository to hold the code of your docusaurus website.

Project Installation

Start by creating a new Docusaurus project with the following command:

npx create-docusaurus@latest my-docs classic

This will install Docusaurus in the directory my-docs and it will use the classic template.

Now, change to the directory my-docs and start the Docusaurus server:

cd my-docs
npm start

This will start the server on localhost:3000 and should open the website automatically in your browser.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

The code for the landing page is in src/pages/index.js. However, this tutorial only focuses on the documentation part.

To open the documentation, click on Tutorial in the Navigation bar. You'll see a few documentation pages created by default with Docusaursus.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Documentation pages reside in the docs 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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Try to change the content of intro.md to the following:

---
sidebar_position: 1
---

# Introduction

I've changed the documentation!

If the server is still running and you go back to the website, you'll see that the content of the page has changed.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

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.

Create a New Document

To create a new document, you need to create a new file under the docs directory.

In this section, you'll create an MDX file to showcase and add some MDX features later in this tutorial.

Create tabs.mdx with the following content:

# How to Use Tabs

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Let's rearrange the position of the link in the sidebar. Add the following at the top of tabs.mdx:

---
sidebar_position: 2
---

This will move "How to Use Tabs" right after "Introduction".

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Optional Features

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.

Use Tabs

Using MDX provides you with a lot of features in your Markdown files. One of those features is adding tabs to your page.

In tabs.mdx add the following after the frontmatter part you added earlier:

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Then, after the heading of the page, add the following to add tabs to the page:

<Tabs groupId="tabs">
  <TabItem value="tab1" label="Tab 1" default>
    I like tab 1
  </TabItem>
  <TabItem value="tab2" label="Tab 2">
    I like tab 2
  </TabItem>
</Tabs>

This will add 2 tabs with each having different text. Notice the following:

  1. The groupId prop on Tabs allows you to synchronize the choice of tab throughout the website.
  2. Each tab item must have a value 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).
  3. The default prop makes a tab selected by default when the page is first opened.

Open the documentation now and you'll see tabs added to the documentation. You can click between the tabs and the text will change.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Let's try adding another Tab component under the previous one:

<Tabs groupId="tabs">
  <TabItem value="tab1" label="Tab 1" default>
    I still like tab 1
  </TabItem>
  <TabItem value="tab2" label="Tab 2">
    I still like tab 2
  </TabItem>
</Tabs>

Notice that Tabs has the same groupId as the previous Tabs element, and the tab items have the same values as well.

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Multi-Language Code Blocks

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.

Below the previous tabs you added add this new tab component:

<Tabs groupId="code-tabs">
  <TabItem value="js" label="JavaScript" default>

  ```js
  console.log("Hello")
  ```
  
  </TabItem>
  <TabItem value="python" label="Python">

  ```py
  print("Hello")
  ```

  </TabItem>
</Tabs>

Notice the following:

  • This Tabs component has a different value for groupId compared to previous tabs. That's because there's no need for synchronization between this Tabs component and previous components.
  • The code blocks inside tabs must be surrounded by empty lines. Otherwise, they will not be rendered properly.
  • The indentation for the code blocks should not be more than one tab (equivalent to 2 spaces) or it might not render properly.

If you open the website now, you'll see tabs for the code blocks.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Add Automatic NPM and Yarn Tabs

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.

In this case, you can make use of the npm2yarn remark plugin. This plugin will allow you to automatically convert all code blocks that use NPM to yarn on your documentation.

Start by installing the npm2yarn plugin:

npm install @docusaurus/remark-plugin-npm2yarn

Then, in docusarus.config.js you need to add a new option remarkPlugins in the config object:

const config = {
	//other options...
    presets: [
        [
          'classic',
          /** @type {import('@docusaurus/preset-classic').Options} */
          ({
              docs: {
                  //other options...
                  remarkPlugins: [
                    [require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}],
          ],
              }
          })
        ]
    ]
};

The {sync: true} option enables synchronizing the user's choice of tab across the website, similar to the behavior you saw earlier with Tabs.

Now, in tabs.mdx add the following at the end:

```bash npm2yarn
npm install react
```

The important bit here is npm2yarn. 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.

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.

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Table of Content

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.

In tabs.mdx under the previous imports add a new import:

import TOCInline from '@theme/TOCInline';

Then, add the following under the heading of the page:

<TOCInline toc={toc} />

## Heading 2
### Heading 3

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Note that the TOCInline component will only render headings starting from h2 or ##. It will not render h1 or # headings.

An important functionality in any documentation is a search engine. In Docusaurus, you can utilize services like Algolia to add a search engine. However, in this tutorial, you'll add a local search engine that works well for small documentation.

In your terminal, run the following command to install the plugin:

npm install --save @easyops-cn/docusaurus-search-local

Then, in docusaurus.config.js add to the config object a new key themes:

themes: [
    [
      require.resolve("@easyops-cn/docusaurus-search-local"),
      {
        hashed: true,
      },
    ],
  ],

That's all you need to add a local search engine.

The search engine will not work if you use npm start. You first need to build the website:

npm run build

Then serve the build:

npm run serve

Open the website again at localhost:3000. You should see a search bar at the right of your navigation bar.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Try searching for one of the pages you added and you should see the results in the dropdown.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Customize Sidebar

The sidebar at the moment is automatically generated from the files in the docs directory. You can, however, manually set the sidebar and items in it.

To do that, open sidebars.js and change the value of the sidebars object to the following:

const sidebars = {
   tutorialSidebar: [
        {
          type: 'doc',
          id: 'intro'
        },
        {
          type: 'category',
          label: 'Tutorial',
          items: [{
            type: 'doc',
            id: 'tabs',
            label: 'Learn all about tabs'
          }],
		}
	]
};

This will change the sidebar to include a link and a collapsable section with one sub-item.

If you open the website now you should see the sidebar changed.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

The prefix URL of this page is set in docusaurus.config.js under the docs object in the presets array in the config object:

docs: {
	editUrl: 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
	},

You should change that to your repository's docs directory. For example:

"https://github.com/shahednasser/docusaurus-tutorial/tree/master/"

The URL prefix should be the URL before reaching the docs directory.

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

Deploy Your Documentation Website

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".

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

You'll then be asked to give Netlify permissions to your GitHub account if you haven't done that before.

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

On the next page, Netlify will show build and deploy settings. They should be similar to the following:

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

If all looks good, click on "Deploy site". Netlify will then build and deploy your site which will take a couple of minutes.

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.

How to Create and Deploy a Documentation Website With Docusaurus and Netlify

If you open your website you'll find that it's exactly similar to what you worked on locally with all features working well.

Conclusion

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.

There's still more to be done with your documentation. Here are some additional steps you can take:

  1. Learn how to customize your domain name in Netlify.
  2. Learn how to manage your documentation's pages and blog.
  3. Check out Docusaurus's documentation to learn about all the features you can add to your documentation.
]]>
<![CDATA[Local Storage vs Cookies: What's the Difference?]]>https://blog.shahednasser.com/localstorage-vs-cookies-whats-the-difference/Ghost__Post__626e658e39840e1ac2875199Thu, 05 May 2022 08:57:19 GMT

Cookies in JavaScript are used to read from and store small data related to the user on the browser.

Local Storage allows you to also read from and store data related to the user on the browser using JavaScript's Storage API.

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.

What are Cookies?

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.

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.

Similarly, as a developer, you'll probably need access to that token to use it for future requests to send to your server.

Cookies on the client-side (the browser) are natively accessed with document.cookies. 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.

What is the Local Storage?

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.

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.

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.

Local storage is accessed using window.localStorage. It's a read-only property with methods like getItem and setItem to access and modify or add data to the local storage.

What are the Differences Between Cookies and Local Storage

Access on the Server

As mentioned in the previous sections, the server can access the client's cookies but not the data stored in the client's storage.

So, in use cases where it's important for the server to have access to a set of data, you should use cookies.

Data Size

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.

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.

Data Expiry

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.

Better API

Unless you're using a JavaScript library to facilitate this, it can be a hassle to read or write cookies using document.cookies as there is no straight way to do it. Here's an example from W3Schools of the code you'd need to use to get and set a cookie by name:

function setCookie(cname, cvalue, exdays) {
  const d = new Date();
  d.setTime(d.getTime() + (exdays*24*60*60*1000));
  let expires = "expires="+ d.toUTCString();
  document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

function getCookie(cname) {
  let name = cname + "=";
  let decodedCookie = decodeURIComponent(document.cookie);
  let ca = decodedCookie.split(';');
  for(let i = 0; i <ca.length; i++) {
    let c = ca[i];
    while (c.charAt(0) == ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) == 0) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}

As for local storage, it implements the Web Storage API which contains easy-to-use methods to read and write data. Here's an example of setting data in the storage and reading them:

localStorage.setItem('name', 'Shahed');

//later
const name = localStorage.getItem('name');

Which Should You Choose?

From reading the differences and definitions this should be clear. However, to summarize it and make it even clearer:

  1. If you need to store data that is accessible for both the server and the client, use cookies. Otherwise, use local storage.
  2. If you need to store larger data, use local storage.
  3. If you need to store data that does not expire, use local storage.
  4. If you need easy-to-use methods to access and modify the data stored on the client, use local storage.

Conclusion

If you're interested to learn more about cookies and local storage, check out MDN's documentation for cookies and localStorage for a more thorough explanation of each.

]]>
<![CDATA[How to use Transitions in React 18]]>https://blog.shahednasser.com/how-to-use-transitions-in-react-18/Ghost__Post__6263f18539840e1ac287510bMon, 25 Apr 2022 09:13:48 GMT

React 18 came out at the end of March with a bundle of new features. One of these new features is Transitions.

In this tutorial, you'll learn more about Transitions in React 18 and see them in action.

Definition

You have 2 types of transitions. Urgent transitions and non-urgent transitions.

Urgent Transitions

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.

Urgent transitions are done the same way you've been setting a state before:

const [name, setName] = useState('');

function handleChange (e) {
	setName(e.target.value); //urgent transition
}

Non-Urgent Transitions

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.

There are 2 ways to start a non-urgent transition. The first one is using the hook useTransition:

import {useTransition, useState} from 'react';

export default function MyApp() {
    const [results, setResults] = useState([]);
    const [pending, startTransition] = useTransition();
    
    function handleChange(e) {
        let tempResults = [];
        ... // set results from APIs
        startTransition(() => {
            setResults(tempResults);
        });
    }
}

The hook returns the boolean variable pending which indicates whether the transition is active or not. It can be used to show a loading component.

The hook also returns a function startTransition that accepts a callback function in which you set the state. The state will not be set immediately.

The second way to start a non-urgent transition is using the function startTransition imported directly from React:

import {startTransition} from 'react';

export default function MyApp() {
    const [results, setResults] = useState([]);
    
    function handleChange(e) {
        let tempResults = [];
        ... // set results from APIs
        startTransition(() => {
            setResults(tempResults);
        });
    }
}

This approach does not give you access to a variable like isPending to check whether the transition is active or not.

This approach is mainly available for places in your code when you can't use hooks like useTransition.

Usage Example

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 Falso.

Start by creating a new React app if you don't have one available:

npx create-react-app my-app

Next, change into the directory my-app:

cd my-app

Then, install the Falso library:

npm i @ngneat/falso

Now, open src/App.js and change it to the following:

import './App.css';

import { useState, useTransition } from 'react';

import { randImg } from '@ngneat/falso';

function App() {
  const [number, setNumber] = useState(5000);
  const [images, setImages] = useState([])
  const [isPending, startTransition] = useTransition();

  function showImages() {
    //TODO add transition
  }

  return (
    <div style={{
      padding: '10px'
    }}>
      <h1>Images</h1>
      <div>
        <label>Number of images</label>
        <input type="number" min="1" max="10000" value={number} onChange={(e) => setNumber(e.target.value)} style={{
          display: 'block',
          marginTop: '10px',
          width: '3rem'
        }} />
        <button type="button" onClick={showImages} style={{marginTop: '10px'}}>Show Images</button>
      </div>
      <div>
        <span>Number selected: {number}</span><br/>
        <span>Results:</span>
        {isPending && <span>Loading...</span>}
        {!isPending && images.length > 0 && images}
      </div>
    </div>
  );
}

export default App;

You first create 2 state variables number and images. You also use useTransition which gives you access to isPending and startTransition.

In the returned JSX, you show a number input and a button that will later retrieve the images on click.

Below the input and button, the number entered by the user in the input will be shown. Notice that in the onChange event handler for the input the name is updated urgently. This will show the number instantly as it is updated by the user.

Let's test it out now. Run the website server:

npm start

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.

Now, let's test the non-urgent transition. In showImages replace the TODO with the following code:

const imgSources = randImg({length: number}).map((url, index) => <img src={`${url}?v=${index}`} key={index} />);
startTransition(() => {
	setImages(imgSources);
})

This will get the images using the falso library and inside startTransition with set the images state variable.

Notice that in the returned JSX of the function we use isPending to indicate whether to show "Loading..." or not.

If you try clicking on the button now, the "Loading..." text will show first, and then the images will be shown gradually.

Conclusion

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.

]]>
<![CDATA[How to Create a Blog with Stackbit and Next.js]]>https://blog.shahednasser.com/how-to-create-a-blog-with-stackbit-and-next-js/Ghost__Post__625ae7a439840e1ac2874f85Wed, 20 Apr 2022 08:10:59 GMT

Stackbit 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.

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.

Project Setup

Start by choosing one of the Starter theme. This tutorial will be focused on the Starter theme.

How to Create a Blog with Stackbit and Next.js

Then, choose a name for your new project.

How to Create a Blog with Stackbit and Next.js

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.

You'll then have your website ready for customization.

How to Create a Blog with Stackbit and Next.js

Notice that your website will be deployed on a free Stackbit subdomain. So, you'll be able to view it online right away.

Transfer Repository to Your Account

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.

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.

How to Create a Blog with Stackbit and Next.js

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.

Once the transfer is done, you'll have your website's codebase in you GitHub account.

Understanding the Branches

In your GitHub repository, you'll have 2 branches: the master branch and the preview branch.

The master branch is the deployed version that everyone can see when they go on your website.

The preview 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.

Set Up Local Development

Stackbit has a code editor that you can use right in your Stackbit app by clicking on the code icon in the sidebar.

How to Create a Blog with Stackbit and Next.js

Once you make a change in the code, it will be automatically committed to the preview branch which is what you see in your Stackbit app.

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.

How to Create a Blog with Stackbit and Next.js

Please note that if you haven't transferred the codebase into your GitHub account you won't be able to see these tips.

As mentioned under "Local Development", once you push commits to the preview branch, the visual editor in your Stackbit app will update automatically.

Creating Posts

There are 2 ways to create posts: through the visual editor or through the code editor.

Visual Editor

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.

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.

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.

How to Create a Blog with Stackbit and Next.js

All changes you make to posts are automatically committed to the preview branch. Once you publish them they'll be live on your deployed website.

Code Editor

To add posts in the code editor, go to content then pages. You'll see all pages there in markdown files, where the names of the files are the slugs of the pages.

You'll also find a blog 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:

---
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
---

This is test post

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.

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.

Once you're done, save the new file and commit it to the preview branch. You'll be able to see it in the visual editor among the CMS.

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.

How to Create a Blog with Stackbit and Next.js

Add Pages for Authors

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.

Add Page to Content Models

Open stackbit.yaml in the root of your website's code and add the following under contentModels:

contentModels:
	...
    PersonFeedLayout:
    	isPage: true
    	singleInstance: true
    	urlPath: '/authors'
    	file: 'authors.md'
    	newFilePath: 'authors.md'

You're adding a new layout PersonFeedLayout. You can read more about content model fields in Stackbit's documentation, but briefly:

  1. If isPage is set to true the UI will allow you to create pages using this model.
  2. singleInstance means that this page can only be created once.
  3. urlPath is the path that this page will be found on.
  4. file is the markdown file that holds the data and content for this page. Since this is a page, its path is relative to content/pages
  5. newFilePath 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 content/pages.

Define the Content Model Fields

In this section, you'll define the fields of the new content model PersonFeedLayout. This means that when you try to create the page through the UI, these fields is what you will see.

To do that, create the file .stackbit/models/PersonFeedLayout.yaml with the following content:

name: PersonFeedLayout
label: Authors
labelField: title
layout: PersonFeedLayout
hideContent: true
extends:
  - Seo
fields:
  - type: string
    name: title
    label: Title
    default: This is a page title
  - type: list
    name: topSections
    label: Top Sections
    items:
      type: model
      groups:
        - sectionComponent
  - type: list
    name: bottomSections
    label: Bottom Sections
    items:
      type: model
      groups:
        - sectionComponent
  - type: style
    name: styles
    styles:
      title:
        fontWeight: ['400', '700']
        fontStyle: ['normal', 'italic']
        textAlign: ['left', 'center', 'right']
    default:
      title:
        textAlign: center

You can learn more about Models in Stackbit through their documentation, but briefly the items under fields are what you'll see in the UI and the fields you can enter for this content model. This content model has 4 fields:

  1. title: the title of the page
  2. topSections: 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.
  3. bottomSections: Similarly to topSections, you'll allow users using the visual editor to add custom sections after the defined layout.
  4. styles: Allow the users using the visual editor to customize some of the style of the layout.

Create New Layout

Next, you'll be creating the PersonFeedLayout which will hold the implementation of the Authors page.

Create a new file src/components/layouts/PersonFeedLayout/index.tsx with the following content:

import * as React from 'react';

import ImageBlock from '../../molecules/ImageBlock';
import { getBaseLayoutComponent } from '../../../utils/base-layout';
import { getComponent } from '../../components-registry';

export default function PageLayout(props) {
    const { page, site } = props;
    const BaseLayout = getBaseLayoutComponent(page.baseLayout, site.baseLayout);
    const topSections = page.topSections || [];
    const authors = page.authors || [];
    const bottomSections = page.bottomSections || [];

    return (
        <BaseLayout page={page} site={site}>
            <main id="main" className="sb-layout sb-page-layout">
                {page.title && (
                    <h1 className="text-center my-5" data-sb-field-path="title">
                        {page.title}
                    </h1>
                )}
                {topSections.length > 0 && (
                    <div data-sb-field-path="sections">
                        {topSections.map((section, index) => {
                            const Component = getComponent(section.type);
                            if (!Component) {
                                throw new Error(`no component matching the page section's type: ${section.type}`);
                            }
                            return <Component key={index} {...section} data-sb-field-path={`sections.${index}`} />;
                        })}
                    </div>
                )}
                <div className='grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-10 my-16 max-w-screen-md mx-auto'>
                    {authors.map((author, index) => (
                        <div className='group text-center' key={index}>
                            {author.image && <ImageBlock {...author.image} 
                                className="group-hover:shadow-md transition-shadow rounded-full w-40 h-40 mx-auto" />}
                            <h3>{author.firstName} {author.lastName}</h3>
                            <span className="text-gray-500">{author.role}</span>
                        </div>
                    ))}
                </div>
                {bottomSections.length > 0 && (
                    <div data-sb-field-path="sections">
                        {bottomSections.map((section, index) => {
                            const Component = getComponent(section.type);
                            if (!Component) {
                                throw new Error(`no component matching the page section's type: ${section.type}`);
                            }
                            return <Component key={index} {...section} data-sb-field-path={`sections.${index}`} />;
                        })}
                    </div>
                )}
            </main>
        </BaseLayout>
    );
}

First, notice that you display the topSections first and the bottomSections last in your layout.

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.

After creating this layout, add it in src/components/layouts/index.tsx:

import PostFeedLayout from './PostFeedLayout';
//...

export {
	...,
    PersonFeedLayout
}

Finally, you need to add it to src/components/components-registry.ts:

const components = {
    //...,
    'PersonFeedLayout': dynamic(() => import('./layouts/PersonFeedLayout'))
};

Add Props

To define the props passed to this layout, first, go to src/utils/data-utils.js and add a new function:

export function getAuthors(objects) {
    return objects.filter((object) => object.type === 'Person');
}

The sourcebit-target-next plugin will use the sourcebit-source-filesystem to read files under content and import them into your Stackbit website.

There are two types of content: pages under the content/pages directory and data under content/data directory. You'll be able to filter out content based on the type field for data content, or the layout field for pages content.

In this case, you're retrieving all authors, which are data content. So, you check if the type field is Person. Please note that, by default, all authors are under content/data/team in JSON files.

Next, you'll use this function to pass the authors as a prop to the layout you created in the previous section. Go to src/utils/static-props-resolvers.js and add the following:

import {
    //...,
    getAuthors
} from './data-utils';

//...

const StaticPropsResolvers = {
    //..,
    PersonFeedLayout: (props, data) => {
        return {
            ...props,
            authors: getAuthors(data.objects)
        };
    }
};

Your Next.js website will resolve the props of the layouts by checking through the StaticPropsResolvers 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.

You add a new key for PersonFeedLayout which accepts props and data as parameters. props is the data entered by the user in the UI for the fields you created for the content model earlier. For example, the bottomSections field.

The data is all the data on your website made available by sourcebit-target-next as explained earlier. It is an object that has 3 properties:

  1. objects which is an array of all content files loaded by the sourcebit-source-filesystem plugin.
  2. pages which is an array holding all static page props.
  3. props which is an object with common props for all pages.

In this function, you return all the props as-is and you add the authors prop which will call the getAuthors function you created earlier passing it data.objects.

Add the Authors Page

Finally, you just need to add the Authors page. Create the file content/pages/authors.md with the following content:

---
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
---

This defines the page to use the PersonFeedLayout and adds among its top sections a Call to Action (CTA) section.

If you run your server now:

npm run dev

and go to /authors, you'll be able to see all the authors in your blog.

How to Create a Blog with Stackbit and Next.js

If you push the changes to the preview branch you'll be able to see your new page in the Stackbit app as well as edit the page fields.

How to Create a Blog with Stackbit and Next.js

Optionally, you can add a link to the page in the header. To do that, open content/data/config.json and add the new link under primaryLinks in header:

{
	...,
    "header": {
    	...,
        "primaryLinks": [
        	...,
            {
                "type": "Link",
                "label": "Authors",
                "altText": "Authors",
                "url": "/authors"
            }
        ]
    }
}

If you save the changes and view the website in local development, or push the changes to the preview branch to view it on the Stackbit app, you'll see a new link the navigation bar for "Authors".

How to Create a Blog with Stackbit and Next.js

Conclusion

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 Stackbit's documentation for more details.

]]>
<![CDATA[10+ Awesome Islamic Tools and Projects]]>https://blog.shahednasser.com/10-awesome-islamic-tools-and-projects/Ghost__Post__625ad95c39840e1ac2874ea3Mon, 18 Apr 2022 09:27:54 GMT

As we are halfway through Ramadan, I want to take a chance to shed light on some cool Islamic tools and projects.

Some of these are open source and you can use them in your own projects as well.

Al Quran Cloud

10+ Awesome Islamic Tools and Projects

Al Quran Cloud is a web app that you can use to read Quran, listen to it with your favorite reciters, and check translations in many languages.

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.

I personally have utilized these APIs in my Chrome extension Quran in New Tab.

You can also support this project on GitHub.

Salat Vue

10+ Awesome Islamic Tools and Projects

Salat Vue 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.

You can support this tool on GitHub.

hijri-date

10+ Awesome Islamic Tools and Projects

hijri-date is an NPM package that you can use to get the Hijri date. It provides a HijriDate 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.

You can support this tool on GitHub.

Quran.com

10+ Awesome Islamic Tools and Projects

Quran.com 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.

You can support this project on GitHub. You can also donate to their organization for more support.

azkar-db

10+ Awesome Islamic Tools and Projects

azkar-db 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.

Unfortunately, this one is all in Arabic only.

Muslim Mate

10+ Awesome Islamic Tools and Projects

Muslim Mate 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.

It's also fully customizable as you can remove or change the places of items in your dashboard.

You can support this project on GitHub.

Al-Adhan

10+ Awesome Islamic Tools and Projects

By the creator of Al Quran Cloud, this website provides you with information about prayer times, as well as a Hijri calendar with events.

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.

You can support this project and contribute to it on GitHub.

Quran-Flutter

10+ Awesome Islamic Tools and Projects

Quran-Flutter 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.

It's Salah Time

10+ Awesome Islamic Tools and Projects

It's Salah Time 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.

You can support and contribute to this project on GitHub.

Sunnah.com

10+ Awesome Islamic Tools and Projects

Sunnah.com 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.

It also provides free-to-use APIs to use these resources in your projects.

You can support and contribute to them on GitHub.

pyIslam

10+ Awesome Islamic Tools and Projects

pyIslam is a Python library that you can use to calculate prayer times, hijri dates, qiblad direction, Zakat calculation, and more.

You can support and contribute to the project on GitHub.

Quran CLI

10+ Awesome Islamic Tools and Projects

Quran CLI 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.

You can read as well as search the Quran right from your CLI. You can view the verses in both English and Arabic.

More Awesome Tools

To check out more awesome Islamic tools, check out the following repositories:

  1. Awesome-Islam
  2. Awesome-Muslims
]]>
<![CDATA[How to Install Python 2 on macOS 12.3+]]>https://blog.shahednasser.com/how-to-install-python-2-on-mac-12-3/Ghost__Post__6258204839840e1ac2874e74Thu, 14 Apr 2022 13:34:57 GMT

As of macOS 12.3+, Python 2 which was installed by default at /usr/bin/python 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.

Install Python 2

To install Python2 again, simply download the macOS universal installer from Python's website

After downloading the installer run it to install Python 2. This will automatically install Python in /usr/local/python as well.

Test it Out

You can run Python 2 in your terminal now and other tools using it will no longer have issues:

python
]]>
<![CDATA[Does Technical Writing Require Technical Knowledge?]]>https://blog.shahednasser.com/does-technical-writing-require-technical-knowledge/Ghost__Post__6251920039840e1ac2874dffMon, 11 Apr 2022 09:10:52 GMT

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.

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.

Documentation

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.

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.

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.

Developer Documentation

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.

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.

You can also rely on the technical team by asking them questions if anything is unclear or you need to confirm some details.

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.

User Documentation

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.

Articles and Blogs

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.

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.

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.

As it is a technical topic, you should have some technical knowledge to be able to write about it correctly.

Conclusion

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.

]]>
<![CDATA[Optional Chaining in JavaScript]]>https://syntackle.live/blog/optional-chaining-in-javascript-D6SuXGtu0-K5hhtZUqqc/Ghost__Post__6248411d39840e1ac2874da6Mon, 04 Apr 2022 09:03:21 GMT

Optional Chaining in JavaScript is used to return undefined for accessing an object property that doesn't exist and whose parent property is nullish (null or undefined).

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.

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.

How it Works

First, let's explore what can go wrong when accessing a property in a nested object.

let person = {
    name: "Murtuza",
    work: () => {
        return "Software Developer"
    },
    socials: {
        github: {
            username: "murtuzaalisurti",
            link: "https://github.com/murtuzaalisurti",
            proUser: {
                is: 'no'
            }
        },
        linkedin: {
            username: "murtuzaali-surti",
            link: "https://linkedin.com/in/murtuzaali-surti"
        },
        twitter: {
            username: "murtuza_surti",
            link: "https://twitter.com/murtuza_surti"
        }
    }
}

In the above object, let's try to access the property link nested within the property website. Can we?

console.log(person.website.link); //an error will be thrown

We get an error,

Cannot read property 'link' of undefined

The property website doesn't exist in the object!

But, let's add the property website to the root object and set the value of it as null.

website: null

Let's check if this works,

console.log(person.website.link); //an error will be thrown

We get a similar error,

Cannot read property 'link' of null

As mentioned in the above definition, we can use optional chaining to handle these types of errors! Here's how we can do that.

Syntax

// website: property to validate
// link: property to access
website?.link

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.

Optional Chaining in JavaScript

Not just that, you can also invoke a function if it exists using optional chaining.

person.work?.(args)

Also, you can access properties using [] brackets.

person.socials.github?.["username"]

What You Can’t Do

  • You cannot apply optional chaining to the objects that are not declared yet. For example:
object?.prop // object is not defined

We haven't declared object, thus it will throw an error.

  • You cannot assign a value to this expression. In other words, the optional chaining expression can't be on the left-hand side.

The below code is not valid.

person.socials.github?.["username"] = "name" // not valid

When to Use Optional Chaining?

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.

For example, in our object person, 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.

person.socials.github?.["username"]

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!

Conclusion

In this article, you learned what Optional Chaining in JavaScript is, how it works when to use it, and when not to use it.

To learn more about how Optional Chaining works, make sure to check out the MDN documentation on it for more details.

]]>
<![CDATA[How I Monetize My Blog]]>https://blog.shahednasser.com/how-i-monetize-my-blog/Ghost__Post__623f0d0d1594e705e60e1956Mon, 28 Mar 2022 10:19:32 GMT

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.

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.

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.

Costs of Creating a Blog

Before you start talking about earning if you're creating your own blog you should think of the spending.

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.

There's a way to obtain both of those things for free, actually. I've listed some resources before in my ultimate guide of things you can do for free.

In my case, I've already purchased a personal domain, so I just used a subdomain of it to use for my blog.

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.

I can host my Gatsby blog on Netlify for free due to their generous free plan. As for the backend, I started off with free hosting on Heroku. 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.

Once I started earning some profit from my blog I switched to hosting my backend on DigitalOcean. Again, as I am the only one using the backend, I opted for one of the cheaper plans.

Summary

If you're considering hosting your own blog my tip for you is:

  1. If you need to get a domain name for free you can either use an existing domain and add a subdomain to it, use free domain name providers, or use subdomains provided by some hosting websites like Netlify.
  2. Consider going for the headless CMS approach to have more flexibility for your hosting.

Alternatively, you can use websites like Medium, Dev.to, or Hashnode to create your own custom blog.

Carbon Ads

One of the most common ways to make a profit off your blog is using ads, so I won't make this one long.

So many blogs go for Google ads. However, in my case, I was able to get Carbon ads 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.

Guest Posts

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.

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.

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.

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.

If you're interested in doing this, you can have a Collaborate or Business page 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.

Article Reviews

On my blog, I have a section called Reviews. 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.

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.

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.

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.

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.

Writing for Other Websites

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.

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.

Conclusion

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.

As your blog grows in quality, more opportunities to monetize it will come your way. Focus on the quality and durability of it first.

]]>
<![CDATA[How to Create and Validate Forms in React using Formik and Yup]]>https://blog.shahednasser.com/how-to-create-and-validate-forms-in-react-using-formik-and-yup/Ghost__Post__6235d3ec1594e705e60e186fMon, 21 Mar 2022 10:55:46 GMT

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.

Formik 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 Yup to make the process even simpler.

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.

You can find the code for this tutorial in this GitHub repository.

Project Setup

In this section, you'll set up your website using Create React App (CRA) and install some dependencies for the sake of the tutorial. If you already have a website set up you can skip this part.

In your terminal, run the following command to create a new React website with CRA:

npx create-react-app react-forms

I'm calling the website react-forms but you can change it to whatever you want.

Once the installation is done, change to the newly created directory:

cd react-forms

Then, install Tailwind CSS to add some styling to your website:

npm install -D tailwindcss postcss autoprefixer

To set up Tailwind CSS create the file tailwind.config.js with the following content:

module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

And replace the content of src/index.css with the following:

@tailwind base;
@tailwind components;
@tailwind utilities;

Create the Form with Formik

You'll now use Formik to create a form. First, install Formik:

npm i formik

Replace the content of src/App.js with the following:

import { useFormik } from 'formik';

function App() {
    const professions = ['Developer', 'Designer', 'Other'];
    //TODO create formik instance
    
    return (
    	<div className="bg-blue-300 min-w-screen min-h-screen overflow-x-hidden">
        </div>
    );
}

export default App;

All you did here is create the component App which does nothing special at the moment.

Notice how you import the useFormik 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.

The useFormik hook accepts as a parameter an object of configurations. These configurations can be used to modify and shape your form as you need.

In this tutorial, you'll use the pass the following properties in the object:

  1. initialValues: includes the form fields and their initial values.
  2. validationSchema: A Yup schema to validate the fields. You'll use this in the next section.
  3. onSubmit: a function to execute when the form is submitted.

Replace the TODO in the App component with the following:

const formik = useFormik({
    initialValues: {
      name: '',
      email: '',
      profession: professions[0],
      age: '',
    },
    onSubmit: function (values) {
      alert(`You are registered! Name: ${values.name}. Email: ${values.email}. Profession: ${values.profession}. 
        Age: ${values.age}`);
    }
  })

As you can see, you set the value of the property initialValues to an object. This object's keys are the names of the fields in the form. Their values are the initial value.

In the onSubmit function, you receive the values 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.

Note that the onSubmit function is only executed once the form is validated. So, you don't need to perform any validation inside this function.

Now, you can use the formik variable to create a form, link its fields to the fields you defined in useFormik, link the validation, and link the submit handler.

formik includes the following properties among others:

  1. handleSubmit: the submit function that should be called when the form is submitted. This is usually assigned to the onSubmit event handler of form elements.
  2. errors: 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.
  3. touched: 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.
  4. values: 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 value property of input elements.
  5. handleChange: A function that should be used as the handler of the change event of input elements. It's passed as the value of the onChange prop of elements.
  6. handleBlur: A function that should be used as the handler of the blur event of input elements. It's passed as the value of the onBlur prop of elements.

Replace the return statement in App with the following:

return (
    <div className="bg-blue-300 min-w-screen min-h-screen overflow-x-hidden">
      <form onSubmit={formik.handleSubmit} className="max-w-lg mx-auto bg-white rounded shadow-lg mt-7 p-3">
      <h1 className='text-3xl mb-3 text-center'>Register</h1>
        <div className='mb-4'>
          <label for="name">Full Name</label>
          <input type="text" name="name" id="name" 
            className={`block w-full rounded border py-1 px-2 ${formik.touched.name && formik.errors.name ? 'border-red-400' : 'border-gray-300'}`}
            onChange={formik.handleChange} onBlur={formik.handleBlur} value={formik.values.name} />
          {formik.touched.name && formik.errors.name && (
            <span className='text-red-400'>{formik.errors.name}</span>
          )}
        </div>
        <div className='mb-4'>
          <label for="email">Email</label>
          <input type="email" name="email" id="email"
            className={`block w-full rounded border py-1 px-2 ${formik.touched.email && formik.errors.email ? 'border-red-400' : 'border-gray-300'}`}
            onChange={formik.handleChange} onBlur={formik.handleBlur} value={formik.values.email} />
          {formik.touched.email && formik.errors.email && (
            <span className='text-red-400'>{formik.errors.email}</span>
          )}
        </div>
        <div className='mb-4'>
          <label for="profession">Profession</label>
          <select name="profession" id="profession"
            className={`block w-full rounded border py-1 px-2 ${formik.touched.profession && formik.errors.profession ? 'border-red-400' : 'border-gray-300'}`}
            onChange={formik.handleChange} onBlur={formik.handleBlur} value={formik.values.profession} >
            {professions.map((profession, index) => (
              <option value={profession} key={index}>{profession}</option>
            ))}
          </select>
          {formik.touched.profession && formik.errors.profession && (
            <span className='text-red-400'>{formik.errors.profession}</span>
          )}
        </div>
        <div className='mb-4'>
          <label for="age">Age</label>
          <input type="number" name="age" id="age"
            className={`block w-full rounded border py-1 px-2 ${formik.touched.age && formik.errors.age ? 'border-red-400' : 'border-gray-300'}`}
            onChange={formik.handleChange} onBlur={formik.handleBlur} value={formik.values.age} />
          {formik.touched.age && formik.errors.age && (
            <span className='text-red-400'>{formik.errors.age}</span>
          )}
        </div>
        <div className='text-center'>
          <button className='bg-blue-500 rounded p-3 text-white' type='submit'>Submit</button>
        </div>
      </form>
    </div>
  );

Notice how you used all the properties in the formik variable mentioned earlier.

Test it Out

The form is now created and ready to be used, even if there's no validation yet.

To test it out, run the server using the following command:

npm start

You can then open the website at localhost:3000 (default port). If you open the website, you'll see the form with 4 fields.

How to Create and Validate Forms in React using Formik and Yup

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.

How to Create and Validate Forms in React using Formik and Yup

Add Validation with Yup

In this section, you'll add validation to the form using Yup.

First, you need to install Yup. Run the following in your terminal:

npm i yup

Yup has a lot of methods and validation rules you can use. The way it works with Formik is you need to create a validation schema and pass it to useFormik as a value to the property validationSchema.

Yup validation schemas are created using Yup.object 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.

Import Yup at the beginning of src/App.js:

import * as Yup from 'yup';

Then, add the property validationSchema to the object passed to useFormik with the following value:

const formik = useFormik({
    ...,
    validationSchema: Yup.object({
      name: Yup.string()
              .label('Full Name')
              .required(),
      email: Yup.string()
              .email()
              .required(),
      profession: Yup.string()
                  .oneOf(professions, 'The profession you chose does not exist'),
      age: Yup.number()
            .min(15, 'You need to be older than 15 to register')
            .required()
    })
  })

You add the following validation rules:

  1. name: Should be a string and is required. You also use the label 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 name.
  2. email: Should be a string, an email, and required.
  3. profession: Should be a string and one of the values in the professions array. You also pass a message as a second parameter to oneOf which will be the message that shows in case there's an error. It's also required.
  4. age: 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.

Test it Out

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.

How to Create and Validate Forms in React using Formik and Yup

If you all values are valid, then the form will be submitted and an alert will show.

Custom Validation Rules

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 test function to add a custom rule.

In this section, you'll add a rule to make sure that the name field has both first and last name.

Change the name property inside the validationSchema to the following:

const formik = useFormik({
    ...,
    validationSchema: Yup.object({
      name: Yup.string()
              .label('Full Name')
              .required()
              .test('is-full-name', 'Please enter both your first and last name', function (value) {
                const nameArr = value.split(" ");
                return nameArr.length >= 2;
              }),
      ...
    })
  })

The first parameter is the name of the custom rule. The second parameter is the message to show in case the field is invalid.

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.

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.

Test it Out

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.

How to Create and Validate Forms in React using Formik and Yup

You'll need to enter at least two words for the field to be valid.

Conclusion

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.

]]>
<![CDATA[Why I Transitioned From a Full-Stack Developer to a Technical Writer]]>https://blog.shahednasser.com/why-i-transitioned-from-a-full-stack-developer-to-a-technical-writer/Ghost__Post__6228bd111594e705e60e17b9Tue, 15 Mar 2022 07:45:23 GMT

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.

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.

Today, I start my new job as a Technical Writer at Medusa. This decision wasn't an easy one and it took me a while to finally make the transition.

In this article, I share with you how I first started technical writing, and why am I transitioning into full-time technical writing.

How it Started

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.

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.

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.

In the past year, I was able to write for a lot of websites and agencies like SitePoint, Draft.dev, LogRocket, and more. I was also able to work with my own clients, which was how I started my journey with Medusa.

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.

Why I Made the Transition

Learn More

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.

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.

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.

Help Beginners

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.

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.

Closer to the Community

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.

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.

Build the Foundation

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.

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.

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.

Conclusion

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.

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.

]]>
<![CDATA[How to Create an NPX Tool]]>https://blog.shahednasser.com/how-to-create-a-npx-tool/Ghost__Post__6220989c1594e705e60e16faTue, 08 Mar 2022 07:58:36 GMT

NPM (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.

However, you've probably seen a lot of libraries or frameworks instructing you to use NPX when installing their packages. React even has a warning that clarifies for developers that using NPX is not a typo.

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.

For example, previously you'd need to install create-react-app globally on your system, then run create-react-app my-website.

Ever since NPM v5.2, there's no need to install create-react-app globally (and it's recommended that you don't). You can simply run npx create-react-app my-website and the same script will run to create your React app.

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.

Prerequisites

This is pretty obvious, but you need Node.js installed to go through this tutorial. Installing Node.js will install in turn NPM and NPX.

Project Setup

Create a new directory that will hold your tool:

mkdir multiply-tool

Next, initialize your project with NPM:

npm init

You'll be asked a few questions about the package such as package name and author name. After you fill them out, a package.json file will be created in the current directory.

Create the Bin File

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 bin field.

Create the directory bin and inside that directory create the file index.js with the following content:

#! /usr/bin/env node
console.log("Hello, World!");

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:

#! /usr/bin/env node

This line should be added to all files that will be executed through the command line. It's called a Shebang, and basically, it specifies what interpreter the file should be passed to for execution in Unix-like systems.

Next, in package.json add the new field bin:

"bin": {
	"multiply": "bin/index.js"
},

This means that when the user runs npx <package_name> the script bin/index.js will run.

Test it Locally

To test it locally, first, install the package globally in your system:

npm i -g

You should run this command inside the directory that holds your package.

Then, in your terminal, run the following command to run your NPX tool:

npx multiply

Here, multiply is the name of the package. If you named your package something else be sure to put the name of the package.

When you run the command, you'll see "Hello, World!" printed in your terminal.

How to Create an NPX Tool

Using Arguments

In this section, you'll implement the functionality of the multiply 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 NaN it means that at least one argument is not a number and the user will see an error in that case as well.

Replace the content of bin/index.js with the following:

#! /usr/bin/env node
const args = process.argv.slice(2);
if (args.length < 2) {
  console.error('Please enter at least 2 numbers');
  process.exit(1); //an error occurred
}

const total = args.reduce((previous, current) => parseFloat(current) * parseFloat(previous));

if (isNaN(total)) {
  console.error('One or more arguments are not numbers');
  process.exit(1); //an error occurred
}

console.log(total);
process.exit(0); //no errors occurred

A few things to note:

  1. process.argv 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 multiply in this case). Any other arguments passed will be available starting from index 2. So, to get the arguments passed by the user you need to slice the array process.argv and get the elements starting from the index 2.
  2. When an error occurs, you can use process.exit(1) to indicate that. If process.exit receives a value other than 0 it means that an error occurred in the CLI tool.
  3. The reduce array function is used to multiply all items in the array one by one.
  4. If the final result of total is NaN, the user will get an error.
  5. If everything is successful, the result will be printed out and the process will exit with 0 indicating that the process ended successfully.

Let's test it out. Run the command again in your terminal passing it 2 numbers:

npx multiply 3 15

You will see the result of the multiplication in your terminal.

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.

Publishing the Package

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 create one.

Then, in your terminal, run the following command to log in using your NPM account:

npm login

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.

To publish your tool, simply run:

npm publish
Note: If you're using a GitHub repository for your project make sure to commit everything before running this command.

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 package.json then try publishing again.

Use Your Published Package

To use your published package, you can run the same command you used earlier when running your local command:

npx <package_name>

Notice how you don't need to install your package globally in this case. You can just run it through NPX.

In my case, I had to rename my package to multiply-tool since multiply already existed in the NPM registry. Then, I ran the following command:

npx multiply-tool 3 15

And received the result of the multiplication:

How to Create an NPX Tool

Update Your Package

To update your package, you can use the following command:

npm version <type>

Where <type> determines how to increment the version. It can be one of the following values:

  1. patch: This will increment the last number in your version and it usually means a small change. For example, it would change the version from 1.0.0 to 1.0.1.
  2. minor: 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 1.0.0 to 1.1.0.
  3. major: 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 1.0.0 to 2.0.0.

After running the above command run the publish command again:

npm publish

And your tool will be updated.

Conclusion

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.

This tool is a simple tool, however, for more complex tools you can use helper libraries like commander and chalk.

]]>
<![CDATA[Learning Python: Week 1 - From Operators to Generators]]>https://blog.shahednasser.com/learning-python-week-1-from-operators-to-generators/Ghost__Post__6217c7d0eb81df0613580407Tue, 01 Mar 2022 10:13:17 GMT

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.

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.

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.

Quick Note

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.

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.

Where I Started

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.

After looking through different websites and python courses online that could help, I decided to learn from learpython.org. The topics seem to be divided up pretty well and each chapter had examples and an exercise at the end.

Up until the time I'm writing this I've finished until Generators.

What I Learned

Indentation

In all programming languages I've used, code blocks are usually wrapped with curly braces { and }. For example, this in JavaScript:

if (x > 1) {
    console.log("x is not 0");
}

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:

if x > 1:
	print("x is not 0")

Simultaneous Assignment

The naming for this might be incorrect but that's what I'm calling it for now.

In Python, you can assign multiple variables simultaneously like this:

a,b = 1,2

This line of code will set a to 1 and b to 2.

Operators

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.

You can use ** to make a power relationship:

a = 2 ** 3 //8

You can use the multiply operator * on strings to repeat them n times:

a = "hello" * 3 //hellohellohello

You can also use the multiply operator * on lists (which are basically arrays in Python) to repeat them as well:

a = [1,2,3] * 3 // [1,2,3,1,2,3,1,2,3]

String Formatting

To format strings and add variables inside strings, you can use the % operator in the string followed by a letter depending on the type of the variable you're inserting in the string.

For example:

print("I am %d years old" % age)

%d is used for integers, %s for strings, %f for float numbers, and %.nf is a float number with n places following the decimal.

Slicing Strings

The brackets [] 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.

However, in Python, you can also use the brackets [] with strings to take substrings of them. If you use the notation [n:m] it will take a slice of the string starting from the index n till the index m.

For example:

x = "My name is Shahed"
print(x[3:10]) //name is

You can also use the notation [n:m:x], where x is the number of steps to take when moving from index n till index m. When you use the notation [n:m] it sets x to 1 by default. x can also be a negative value if you want to slice the string in reverse.

Boolean Operators

Most languages use && to specify an "and" condition, and || to specify an "or" condition.

In Python, you use and for "and" and or for "or". This is part of what makes Python human-readable.

For example:

if x == 2 and y == 3:
	print("x is 2 and y is 3")

Other operators are in to check if an item is in an iterable object like a list, is to check if 2 variables match in both value and reference, and not to negate a boolean expression.

Else in Loops

else is usually used with if conditions, where you perform an action if the condition is not true.

In Python, else can be used with loops to perform an action when the condition of the loop fails.

For example:

for i in range(1,5):
	print("i is less than 5")
else:
	print("i is greater than 5")

If you use break inside the loop, then the else block won't be executed. If you use continue inside the loop, the else block will be executed.

init Function in Classes

In Python, the function __init__ in a class is the function that is first called when the class is created. It's the equivalent of the constructor function in other languages.

Modules

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.

To import a module:

import user

Where user is a file in the same directory with the name user.py

You can then access functions in that module using the . notation:

user.create()

Alternatively, you can import the function directly:

from user import create

You can also import all objects in the module:

from user import *

You can then use the objects directly:

create()

In addition, you can import modules with aliases:

import user as my_user

Packages

Packages are directories that hold other packages and modules. Each package should include the file __init__.py, even if it's empty. It's used to indicate that the current directory is a package.

Modules can be imported from inside that package. For example, if you create the directory blog and it has the user module inside it, you can import it like this:

import blog.user

Or alternatively:

from blog import user

By default, all modules inside a package can be imported. You can specify which modules can be accessed in a package by assigning the __all__ variable in __init__:

__all__ = ["user"]

Numpy Arrays

Numpy arrays are like lists, but they are more fast and efficient. Using Numpy arrays you can easily perform a lot of tedious tasks.

For example, you can perform operations on all elements in a Numpy array:

np_array = np.array([1,2,3])

np_array = np_array * 2 //[2,4,6]

You can also use [] to take a subset of items in the Numpy array. For example:

np_array = np.array([1,2,3])

np_array[np_array > 1] //[2,3]

Where np_array > 1 will return a new Numpy array but instead of the original values it will be either True or False based on whether each element satisfies the condition or not. If you then pass it as an index to np_array it will return a Numpy array with only the elements that test true for that condition.

Pandas DataFrame

DataFrames in Pandas allow you to store data in a table-like structure where there are columns and rows.

DataFrames can be created from dictionaries. They can also be created from CSV files.

You can access the data using a column name as an index:

dataframe["name"]

This will return the data as a Pandas Series. You can use double brackets to have it be returned as a DataFrame:

dataframe[["name"]]

You can also return multiple columns or indices:

dataframe[["name", "age"]]

Another way of getting a set of data from the DataFrame is using loc and iloc, where loc accesses the data using a label index, while iloc accesses the data using a numeric index. It's helpful if you have a specific row and column to access.

Generators

Generators are used to implement iterators. They are functions that use the keyword yield to return an iterable set of items.

When you run an iteration over the generator function, the generator starts. Everytime the yield keyword is reached, the value is returned as the value for the current iteration.

For example:

def age():
	for i in range(5):
    	yield "I am %d years old" % i

for str in age():
	print(str)

This will print:

I am 0 years old
I am 1 years old
I am 2 years old
I am 3 years old
I am 4 years old

Where Next?

There are still more chapters to go through in learnpython.org, however, I think I want to practice solving some problems as well.

A platform that I found good reviews for among Python learners and developers is CheckiO. So, I'll probably start learning through this platform while also continuing on with some of the other chapters.

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!

]]>
<![CDATA[Cross-Post CLI Tool: New Features and Fixes]]>https://blog.shahednasser.com/cross-post-cli-tool-new-features-and-fixes/Ghost__Post__621c858deb81df0613580535Mon, 28 Feb 2022 09:05:19 GMT

Almost a year ago, I wrote about how I created a CLI tool to cross-post 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.

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.

On Monday, the 28th of February, I pushed out a new release of cross-post-blog with the version 1.3.0. I'll be sharing some of the features and fixes it includes. You can also check out the GitHub repository for more information about the library.

If you're reading this article on Dev.to, Hashnode, or Medium, then it is reposted from my own blog using the Cross-Post CLI tool!

Posting From Local Files

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 -l or --local option to your command.

For example:

cross-post run /path/to/test.md -l

This will post a local file test.md to all of the platforms.

You can also use it with all of the options you previously used.

Changed Markdown Converter

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.

I previously was using node-html-markdown. It worked fine in terms of functionality. However, there were some issues related to how it parsed code blocks.

The new version is now using turndown 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.

Added Title Selector

Previously, you could set a default article and image selectors in the configuration. You could also override those configurations in the run command.

N0w, you can also set the default title selector in your configuration:

cross-post config titleConfig

Or, pass it as an option -ts or --title-selector to the run command:

cross-post run <url> -ts .post-full-title

Upcoming Features

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 update posts.

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!

How to Install or Update

If you want to install and start using Cross-Post or update your version you can install it with NPM:

npm i -g cross-post-blog

Please check the README for more information on installing and using this tool.

Contribution

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 existing issues or add new features, then please don't hesitate!

]]>
<![CDATA[How to Read and Write CSV Files Using Node.js and Express]]>https://blog.shahednasser.com/how-to-read-and-write-csv-files-using-node-js-and-express/Ghost__Post__620a3586eb81df0613580321Tue, 22 Feb 2022 10:35:58 GMT

Node.js can be used to build a variety of apps and websites. It's most popularly used with Express to create a server for your websites and apps.

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 this GitHub Repository.

Project Setup

You'll start by setting up the server with NPM.

Run the following command to create a new directory and initialize the project with NPM:

mkdir node-csv
npm init -y

Then, you need to install the dependencies needed for the project:

npm i express body-parser nodemon

This will install express to create a server, body-parser to parse the body of the requests, and nodemon to make sure that the server restarts whenever there are new changes in the files.

After that, create index.js with the following content:

const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const port = 3000

app.use(bodyParser.json())
app.use(express.static('public'))

app.listen(port, () => {
  console.log(`App listening on port ${port}`)
})

This will initialize your server.

Finally, add the start script command in package.json:

"scripts": {
    "start": "nodemon index.js"
},

Now, you can start the server by running the following command:

npm start

This will start the server on localhost:3000.

Write CSV Files

The first part of this tutorial will go over how you can write CSV files.

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.

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.

Start by installing the necessary dependency for this functionality:

npm i csv-stringify

Create the file public/create.html with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
  <link href="https://unpkg.com/tabulator-tables/dist/css/tabulator.min.css" rel="stylesheet">
  <title>Create CSV</title>
</head>
<body>
  <div class="container py-4">
    <h1>Create CSV</h1>
    <h2>Add Columns</h2>
    <input type="text" name="column" id="columnName" class="form-control" placeholder="Column Name" />
    <button class="btn btn-primary mt-1" id="addColumn">Add</button>
    <h2 class="mt-3">Column Data</h2>
    <button class="btn btn-primary mb-3" id="addRow">Add Row</button>
    <div id="csvTable"></div>
    <button class="btn btn-primary mt-3" id="submitForm">Create CSV</button>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" 
    integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"></script>
  <script>
    const columnNameInput = document.getElementById('columnName');
    const addColumnButton = document.getElementById('addColumn');
    const addRowButton = document.getElementById('addRow');
    const submitFormButton = document.getElementById('submitForm');

    const table = new Tabulator("#csvTable", {
      height:"300px",
      data: [], //assign data to table
      movableColumns: true, 
      addRowPos: "bottom",
    });

    addColumnButton.addEventListener('click', () => {
      const name = columnNameInput.value ? columnNameInput.value.trim() : '';
      if (!name) {
        alert("Please add a name");
        return;
      }

      table.addColumn({title: name, field: name.toLowerCase(), editableTitle: true, editor: true});
      columnNameInput.value = '';
    });

    addRowButton.addEventListener('click', () => {
      table.addRow({});
    });

    submitFormButton.addEventListener('click', () => {
      const data = table.getData();

      fetch('/create', {
        method: 'POST',
        body: JSON.stringify({
          data
        }),
        headers: {
          'Content-Type': 'application/json'
        }
      })
      .then((response) => response.blob())
      .then((blob) => {
        const fileURL = URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = fileURL
        a.download = "file.csv"
        a.click()
      })
      .catch((e) => {
        console.error(e)
        alert(e.message)
      })
    })
  </script>
</body>
</html>

This page will allow the user to create a CSV file. For simplicity, you're using Bootstrap for easy styling and Tabulator to easily create a table with modifiable columns and rows.

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 POST request to the create endpoint (which you'll create next) with the data. Then, the received file will be downloaded.

Next, you'll create the create endpoint. Open index.js and add the following require statement at the beginning of the file:

const fs = require('fs')
const stringify = require('csv-stringify').stringify

You'll use fs to create the CSV file and stringify from the csv-stringify library.

Next, add the following new endpoint to your server:

app.post('/create', (req, res) => {
  const data = req.body.data

  if (!data || !data.length) {
    return res.status(400).json({success: false, message: 'Please enter at least 1 row'})
  }

  stringify(data, {
    header: true
  }, function (err, str) {
    const path = './files/' + Date.now() + '.csv'
    //create the files directory if it doesn't exist
    if (!fs.existsSync('./files')) {
      fs.mkdirSync('./files')
    }
    fs.writeFile(path, str, function (err) {
      if (err) {
        console.error(err)
        return res.status(400).json({success: false, message: 'An error occurred'})
      }

      res.download(path, 'file.csv')
    })
  })
})

This will first validate the data sent. Then, you'll use the stringify function to create the CSV string. This function takes the data to be stringified as the first parameter, an object of options as the second parameter, and a callback function as the third.

The header option makes sure to include the column names as the header of the CSV file.

In the callback function, you create a file using fs in the directory files using writeFile. The file will contain the CSV string created by stringify. In the callback function of writeFile you return the CSV file for download.

Now, if you run the server (if it's not already running) and go to localhost:3000/create.html you'll see the page you created earlier in public/create.html. Try adding a few columns and rows into the table.

How to Read and Write CSV Files Using Node.js and Express

Once you're done, click the "Create CSV" button. This will send the data to the server at the create endpoint you created. Then, the endpoint will return a file for download which will then initiate a download in the user's browser.

Read a CSV File

In this section, you'll learn how to read a CSV file in Node.js and Express. The user will upload a CSV file.

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.

To parse a CSV file, you'll use CSV Parse. You'll also use Express Multer Middleware to handle file upload.

Start by downloading the necessary dependencies:

npm i multer csv-parse

N0w, create the file public/read.html with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Read CSV</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
  <link href="https://unpkg.com/tabulator-tables/dist/css/tabulator.min.css" rel="stylesheet">
</head>
<body>
  <div class="container py-4">
    <h1>Read CSV</h1>
    <label for="file">Choose file to read</label>
    <input type="file" class="form-control" name="file" id="file" />
    <button class="btn btn-primary mt-2" id="submitFile">Read</button>
    <div class="mt-2" id="csvTable"></div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" 
    integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"></script>
  <script>
    const fileInput = document.getElementById('file')
    const submitFile = document.getElementById('submitFile')
    let file = null

    fileInput.addEventListener('change', function () {
      file = this.files[0]
    })

    submitFile.addEventListener('click', function () {
      if (!file || file.type !== 'text/csv') {
        alert('Please choose a CSV file')
        return
      }

      const formData = new FormData()
      formData.append('file', file)

      fetch('/read', {
        method: 'POST',
        body: formData
      })
      .then((response) => response.json())
      .then(({ data }) => {
        if (data.length) {
          const columns = data[0]
          const rows = data.splice(1).map((arr) => {
            const obj = {}
            columns.forEach((column, index) => {
              obj[column] = arr[index]
            })
            return obj
          })

          console.log(rows, columns)
          
          const table = new Tabulator("#csvTable", {
            height:"300px",
            data: rows,
            autoColumns: true
          });
        } else {
          alert('The CSV is empty')
        }
      })
      .catch((e) => alert(e.message))
    })
  </script>
</body>
</html>

Just like create.html this file uses Bootstrap for easy styling and Tabulator to easily show the CSV file in a table.

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 read (which you'll create next). Then, using the data the server creates you'll show the data in a Tabulator table.

Now, you need to add the read endpoint.

In index.js, add the following require statements at the beginning of the file:

const parse = require('csv-parse').parse
const os = require('os')
const multer  = require('multer')
const upload = multer({ dest: os.tmpdir() })

Notice that you also initialize multer and specify the destination as the tmp directory of the operating system. This is because you don't need to actually store the file anywhere for this tutorial.

Also, note that you'll need to use fs as well. So, if you didn't follow along with the previous section make sure to require it here as well.

Then, add the following new endpoint:

app.post('/read', upload.single('file'), (req, res) => {
  const file = req.file

  const data = fs.readFileSync(file.path)
  parse(data, (err, records) => {
    if (err) {
      console.error(err)
      return res.status(400).json({success: false, message: 'An error occurred'})
    }

    return res.json({data: records})
  })
})

You first read the file using fs.readFileSync. Then, you parse the file data using parse from csv-parse.

If an error occurs, you return an error message to the user. Otherwise, you return the data.

Run the server if it's not running already then go to localhost:3000/read.html. You'll see a file input with a button.

How to Read and Write CSV Files Using Node.js and Express

Choose a CSV file then click read. The file data will be displayed in a table using Tabulator.

How to Read and Write CSV Files Using Node.js and Express

Conclusion

In this tutorial, you learned how you can read and write CSV files in Node.js and Express. You used the libraries CSV Parse and CSV Stringify 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.

]]>
<![CDATA[How to Style a Scrollbar with CSS]]>https://blog.shahednasser.com/how-to-style-a-scrollbar-with-css/Ghost__Post__61fa773460a9ab05cc5e69deTue, 15 Feb 2022 10:00:19 GMT

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!

However, styling the scrollbar can be tricky in CSS. You'll need to use pseudo-element selectors.

In this article, you'll learn how you can style a scrollbar with CSS and which pseudo-element selectors you need to use.

Pseudo-Element Selectos Compatibility

The pseudo-element selectors mentioned in this tutorial will only work on Webkit browsers. So, it will work on most modern browsers like Chrome and Safari.

However, they will not work on Firefox. Alternatively, you can use the scrollbar-width and scrollbar-color properties.

::-webkit-scrollbar

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.

Note that if this selector is used on a specific element (not the scrollbar of the entire page), then you need to specify overflow: scroll; on the element, or else the scrollbar won't show.

Apply the following styling to set the width of the page's scrollbar:

::-webkit-scrollbar {
    width: 30px;
}

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.

::-webkit-scrollbar-thumb

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.

For example, you can use this selector to make its background red and give it a border-radius:

::-webkit-scrollbar-thumb {
    background: #ef4444;
    border-radius: 20px;
}
How to Style a Scrollbar with CSS

::-webkit-scrollbar-track

You can use this pseudo-element selector to style the track. This is the part that is below the thumb.

Another pseudo-element selector that can be used is ::-webkit-scrollbar-track-piece, which is the part of the scrollbar not covered by the handler. The ::-webkit-scrollbar-track-piece is on a higher layer than ::-webkit-scrollbar-track.

For example, you can use it to add a background color to the track:

::-webkit-scrollbar-track {
    background-color: #fca5a5;
}
How to Style a Scrollbar with CSS

::-webkit-scrollbar-button

You can use this to style the up and down (or left and right for horizontal scrollbars) buttons.

This will apply styling to all scrollbar buttons. This means it will apply the styling for both the horizontal and vertical scrollbar buttons.

To apply specific styling for specific buttons here's what you need to use:

  1. ::-webkit-scrollbar-button:vertical:start: This is for the up button in the vertical scrollbar.
  2. ::-webkit-scrollbar-button:vertical:end: This is for the down button in the vertical scrollbar.
  3. ::-webkit-scrollbar-button:horizontal:start: This is for the left button in the horizontal scrollbar.
  4. ::-webkit-scrollbar-button:horizontal:end: This is for the right button in the horizontal scrollbar.

Additionally, each button has a :increment and :decrement selector.

In this example, I'll add styling for the buttons of a vertical scrollbar:

::-webkit-scrollbar-button {
    display: block;
    background-color: #b91c1c;
    background-repeat: no-repeat;   
    background-size: 50%;
    background-position: center;
}

::-webkit-scrollbar-button:vertical:start:increment {
    background-image: url('https://upload.wikimedia.org/wikipedia/commons/7/7e/Chevron-up.svg');   
}

::-webkit-scrollbar-button:vertical:start:decrement {
    display: none;
}

::-webkit-scrollbar-button:vertical:end:increment {
    display: none;
}

::-webkit-scrollbar-button:vertical:end:decrement {
    background-image: url('https://upload.wikimedia.org/wikipedia/commons/e/ee/Chevron-down.svg');   
}

The properties in ::-webkit-scrollbar-button will apply for all scrollbar buttons. In the example, I add a background color. I also set the display to block 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.

The ::-webkit-scrollbar-button:vertical:start:increment 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.

The ::-webkit-scrollbar-button:vertical:start:decrement 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.

The ::-webkit-scrollbar-button:vertical:end:increment 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.

The ::-webkit-scrollbar-button:vertical:end:decrement 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.

::-webkit-scrollbar-corner

This pseudo-element selector is used to style the space between the vertical and horizontal scrollbars.

How to Style a Scrollbar with CSS

For example, you can use it to set different background color:

::-webkit-scrollbar-corner {
    background-color: #7f1d1d;
}
How to Style a Scrollbar with CSS

Conclusion

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.

As mentioned earlier, these selectors will only work on Webkit browsers. Please check out MDN's browser compatibility table for further information.

]]>
<![CDATA[How to Create a Notes App with Strapi v4 and React Native]]>https://blog.shahednasser.com/how-to-create-notes-app-with-strapi-v4-and-react-native/Ghost__Post__61f9452160a9ab05cc5e689aTue, 08 Feb 2022 10:23:54 GMT

Strapi 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.

One of the many frameworks you can integrate Strapi to is React Native. React Native is a cross-platform framework that allows you to write your code in JavaScript, then deploy it on Android and iOS.

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.

You can find the code for this tutorial on this GitHub repository.

Setup Strapi

In your terminal, run the following command to install and setup Strapi:

npx create-strapi-app@latest strapi --quickstart

This will create a new directory called strapi, and, once the installation is done, a new page will open in your default browser at the Strapi backend. It's usually at localhost:1337.

How to Create a Notes App with Strapi v4 and React Native

You'll need to create an admin user. Once you're done, you'll be redirected to the admin dashboard.

How to Create a Notes App with Strapi v4 and React Native

Create Content-Types

Click on Content-Type Builder on the sidebar. Then, click on Create new collection type under Collection Types.

In the pop-up, enter Note for display name. Then click continue.

You'll create 3 fields:

  1. title: of type Text. Make sure to set it required in the Advanced Settings tab.
  2. content: of type Rich Text. Make sure to set it required in the Advanced Settings tab.
  3. date: of type Date. Make sure to select datetime in the Type dropdown, and set it required in the Advanced Settings tab.

You should have a Note collection type with the following fields:

How to Create a Notes App with Strapi v4 and React Native

Once you're done click Save.

Change Permissions

The next step is to change permissions so that you can access the notes from React Native.

Click on Settings in the sidebar, then go to Roles under Users & Permissions Plugin. You'll see two entries in the table. Click on the edit icon for the Public row.

How to Create a Notes App with Strapi v4 and React Native

Then, scroll down. Under Permissions, click on Note to expand it, then select all permissions. Once you're done, click Save at the top right.

How to Create a Notes App with Strapi v4 and React Native

Setup React Native

Next, you'll set up a React Native project.

First, you need to install the Expo CLI if you don't have it installed:

npm i -g expo-cli

Next, run the following command to create a new React Native project:

expo init notes-app

Choose Blank when asked about the type of project to create.

Once that is done, change to the newly created directory notes-app and install dependencies with NPM:

cd notes-app
npm i

Now, you'll need to install the dependencies you'll need for this tutorial. First, start by installing some dependencies with Expo's CLI:

expo install react-native-screens react-native-safe-area-context

These dependencies are necessary to add React Navigation, which is a library that adds navigation capabilities between screens in your app.

Suggested Read: React Native Navigation Tutorial.

Next, install the necessary dependencies with NPM:

npm i react-native-paper @react-navigation/native @react-navigation/native-stack react-native-pell-rich-editor react-native-webview

Here's what each dependency is for:

  1. react-native-paper: React Native Paper library to easily add styled-components in your app.
  2. @react-navigation/native @react-navigation/native-stack: More libraries for React Navigation.
  3. react-native-pell-rich-editor: a Rich Editor element for React Native.
  4. react-native-webview: required by react-native-pell-rich-editor.

Create Home Screen

The home screen displays a list of notes with just the title and the date. It will also have a + button at the top right to add notes.

Create the file screens/HomeScreen.js with the following content:

import axios from "axios";
import { useEffect, useState } from "react";
import { FlatList, View } from "react-native";
import { Caption, List, Snackbar } from "react-native-paper";

export default function HomeScreen ({ navigation }) {
  const [notes, setNotes] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');

  useEffect(() => {
    loadNotes()

    const subscribe = navigation.addListener('focus', () => {
      loadNotes();
    });

    return subscribe;
  }, [])

  function loadNotes () {
    axios.get('http://<IP>:1337/api/notes')
      .then(({ data }) => {
        setNotes(data.data);
        setLoading(false);
      })
      .catch((e) => {
        console.error(e);
        setError('An error occurred, please try again later.');
        setLoading(false);
      });
  }

  return (
    <View>
      {!loading && !notes.length && <Caption style={{textAlign: 'center', marginTop: 10}}>You have no notes</Caption>}
      <FlatList
        data={notes}
        renderItem={({ item }) => (
          <List.Item 
            key={item.id}
            title={item.attributes.title}
            description={item.attributes.date}
            onPress={() => navigation.navigate('Editor', {
                note: item
            })}
            />
        )}      
        refreshing={loading}
        onRefresh={loadNotes}
        style={{width: '100%', height: '100%'}}
      />
      <Snackbar visible={error.length > 0} onDismiss={() => setError('')}>{error}</Snackbar>
    </View>
  )
}

You first create the state variable notes which will hold the notes when received from the Strapi backend. You use a FlatList component to display the notes. This will render each note using the List.Item 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.

When the item in the list is clicked, the user will be taken to the Editor screen (which you'll create in the next section).

The fetching of the notes will happen in the loadNotes function. This function is called when the screen first opens, when the screen gains focus, and when the flat list is refreshed.

In the loadNotes function, you send a request to http://<IP>:1337/api/notes. Notice that to run the app on your phone, you need to use your machine's network IP. So, replace <IP> with your machine's IP.

This endpoint is Strapi's Endpoint for fetching the entries of a content type. You then set the notes state variable to the data received from Strapi.

Next, you need to make changes to the App.js file to show different screens.

Open App.js and replace the content with the following:

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { IconButton } from 'react-native-paper';
import EditorScreen from './screens/EditorScreen';
import HomeScreen from './screens/HomeScreen';

const Stack = createNativeStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} options={({navigation}) => ({
          headerRight: () => (
            <IconButton icon='plus' onPress={() => navigation.navigate('Editor')} />
          )
        })} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Notice that the Home screen has a button at the top right that will take you to the Editor screen.

Now, let's run the app. In your terminal, run the following:

npm start

This will allow you to open the app on iOS or Android. You'll need the Expo Go 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.

When you open the app, you'll see an empty home screen.

How to Create a Notes App with Strapi v4 and React Native

Create Editor Screen

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.

Create screens/EditorScreen.js with the following content:

import { useLayoutEffect, useRef, useState } from 'react';
import { RichEditor, RichToolbar} from "react-native-pell-rich-editor";
import { Keyboard, KeyboardAvoidingView, ScrollView, View } from 'react-native';
import { Button, Colors, Snackbar, Subheading, TextInput } from 'react-native-paper';
import axios from 'axios';

export default function EditorScreen ({ route, navigation }) {
  const editor = useRef();
  const [title, setTitle] = useState(route.params && route.params.note ? route.params.note.attributes.title : '');
  const [content, setContent] = useState(route.params && route.params.note ? route.params.note.attributes.content : '');
  const [error, setError] = useState('')

  function saveNote () {
    editor.current.blurContentEditor(); //lose focus for editor and close keyboard
    Keyboard.dismiss();
    const trimmedTitle = title.trim(),
      trimmedContent = content.trim();
    if (!trimmedTitle.length || !trimmedContent.length) {
      setError('Please fill both title and content');
      return;
    }
    axios({
      method: route.params && route.params.note ? 'PUT' : 'POST',
      url: 'http://<IP>:1337/api/notes' + (route.params && route.params.note ? '/' + route.params.note.id : ''),
      data: {
        data: {
          title,
          content,
          date: Date.now()
        }
      }
    }).then(() => {
      //redirect back to home screen
      navigation.goBack();
    })
    .catch((e) => {
      console.error(e);
      setError('An error occurred, please try again later')
    })
  }

  function deleteNote () {
    axios.delete('http://<IP>:1337/api/notes/' + route.params.note.id)
      .then(() => {
        //redirect back to home screen
      navigation.goBack();
      })
      .catch((e) => {
        console.error(e);
        setError('An error occurred, please try again later.');
      })
  }

  useLayoutEffect(() => {
    navigation.setOptions({
      headerTitle: content.length === 0 ? 'New Note' : 'Edit Note',
      headerRight: route.params && route.params.note ? () => (
        <Button color={Colors.redA100} onPress={deleteNote}>Delete</Button>
      ) : () => (<></>)
    });
  }, []);

  return (
    <View style={{margin: 10, flex: 1, justifyContent: 'space-between'}}>
      <TextInput label="Title" value={title} onChangeText={setTitle} mode="outlined" />
      <Subheading>Content</Subheading>
      <RichToolbar
        editor={editor}
      />
      <ScrollView keyboardDismissMode='onDrag'>
        <KeyboardAvoidingView behavior={"position"}	style={{ flex: 1 }} keyboardVerticalOffset={250}>
          <RichEditor 
            style={{ flex: 1}}
            ref={editor} 
            onChange={setContent} 
            initialContentHTML={content} 
            placeholder='Start typing...'
            useContainer />
          <Button onPress={saveNote} mode="contained" style={{marginTop: 20}}>
            Save
          </Button>
        </KeyboardAvoidingView>
      </ScrollView>
      <Snackbar visible={error.length > 0} onDismiss={() => setError('')}>{error}</Snackbar>
    </View>
  )
}

In this code snippet, you create a editor ref variable for the Rich text editor. This is necessary for the library you're using. You also create a title and content 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.

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.

Save a Note

When the Save button is clicked, you check if the note exists or is new. If the note already exists, then, a PUT request is sent to http://<IP>:1337/api/notes/<note_id>, where <IP> is your machine's IP and <note_id> is the current note's ID. This Strapi endpoint is used to update an entry in a collection.

Alternatively, if the note is new, a POST request is sent to http://<IP>:1337/api/notes, where <IP> is your machine's IP. This Strapi endpoint is used to create an entry.

Both requests accept in the body of the request a data parameter with the entry's data. You pass the title, content, and current date.

Delete a Note

When the Delete Button is clicked, a DELETE request is sent to http://<IP>:1337/api/notes/<note_id>, where <IP> is your machine's IP and <note_id> is the ID of the note to delete. Remember, this is only available if the note exists.

After the note is saved or deleted, you take the user back to the home screen.

Next, you need to add the new screen to App.js. Add it after the Home screen:

<Stack.Screen name="Editor" component={EditorScreen} />

That's all, now run the app if it's not running. Try first clicking on the + button at the top right of the home screen. You'll see a rich text editor with a toolbar and a Save button.

How to Create a Notes App with Strapi v4 and React Native

Add a Note

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.

How to Create a Notes App with Strapi v4 and React Native

Edit a Note

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.

Delete a Note

If you click on a note from the home screen, you'll notice a delete button at the top right of the screen.

How to Create a Notes App with Strapi v4 and React Native

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.

Conclusion

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.

]]>
<![CDATA[What is Intuitive Design and Why is It Important?]]>https://blog.shahednasser.com/what-is-intuitive-design-and-why-is-it-important/Ghost__Post__61f02d6ae37d1cfea32a7ee4Tue, 01 Feb 2022 11:56:45 GMT

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.

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.

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.

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.

In this article, you'll learn more about what intuitive design is, why it's important for your websites and apps.

What is Intuitive Design

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.

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.

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.

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.

Ok, but how do I expect users to just know 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.

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.

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.

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!"

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.

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".

Why is Intuitive Design Important?

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.

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.

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.

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.

Conclusion

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.

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.

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.

]]>
<![CDATA[How to Internationalize (i18n) a React App with Transifex Native]]>https://blog.shahednasser.com/how-to-internationalize-i18n-a-react-app-with-transifex-native/Ghost__Post__61efd82ce37d1cfea32a7e97Wed, 26 Jan 2022 08:12:44 GMT

React is one of the most popular JavaScript frontend frameworks. It allows you to create responsive, reactive, and blazingly fast websites and apps. You can create almost any type of website with React.

One issue that you’ll run into when you create a React app is internationalizing it. Internationalization (or i18n) is adding support for multiple languages to your website. The process includes both translating the content as well as modifying the style to support the language’s direction.

There are many solutions out there, and in a previous tutorial, I went through how you can internationalize a React app using i18next. i18next is an open-source internationalization solution that allows you to internationalize a lot of types of projects, including a React app.

Another internationalization solution for React is Transifex Native. Transifex is a localization platform that makes internationalizing your projects, including your React project, much easier. Transifex bridges the gap between developers and translators, as it allows you to focus on the programming part while also working with translators to translate your website even if they’re not tech-savvy.

In this article, you’ll learn how to internationalize a React app using Transifex Native. I’ll be creating a website that’s exactly similar to the one I created in my tutorial for internationalization with i18next. This will allow you to see the comparison between the two more clearly and see which is a better option.

You can find the code for this tutorial on this GitHub repository.

Create a Transifex Account

The first step that you should take is to create a Transifex account. Transifex has a 15-day free trial and a free-forever plan for open-source projects!

After you create an account, you’ll be asked to create a project. You’ll need to enter a project name. Then, for project type choose “Native”. Finally, you need to enter the main language of your website and what language(s) you’ll be translating your website to. In my case, I’ll choose English as the main language and Arabic as the target language.

How to Internationalize (i18n) a React App with Transifex Native

Once you’re done, click on Create Project.

On the next page, you’ll see instructions on how to create credentials for your project. Click on Generate Native Credentials Now at the bottom of the page.

How to Internationalize (i18n) a React App with Transifex Native

This will open a pop-up where you can see the API token and secret. Make sure to copy both the keys as you’ll need them later.

Once that is done, you can start creating your React app and internationalizing it!

Create React App

In your terminal, run the following command:

npx create-react-app transifex-i18n

This will create the directory transifex-i18n with the React app inside. Change to that directory:

cd transifex-i18n

Install Dependencies

Now, you’ll install the dependencies that you’ll need for this tutorial. First, install React Bootstrap for easy styling:

npm install react-bootstrap@next bootstrap@5.1.0

Then, install Transifex Native’s libraries that are essential for internationalizing a React app:

npm install --save @transifex/native @transifex/react @transifex/cli

@transifex/native is the core Transifex Native library. @transifex/react is the React SDK that you can use in React projects. It provides an easy and React-compatible interface for the core library. @transifex/cli is a CLI tool that you’ll use to sync translatable strings between your codebase and your Transifex Native project.

Create Components

You’ll now create some components that you’ll use for your website.

Create src/components/Greeting.js with the following content:

function Greeting () {
  return (
    <h1>
      Hello
    </h1>
  );
}
export default Greeting;

Create src/components/Text.js with the following content:

function Text () {
  return (
    <p>
      Thank you for visiting our website.
    </p>
  )
}
export default Text;

Create src/components/Navigation.js with the following content:

import { Container, Nav, Navbar, NavDropdown } from "react-bootstrap";
import { Container, Nav, Navbar, NavDropdown } from "react-bootstrap";

function Navigation () {

  return (
    <Navbar bg="light" expand="lg">
      <Container>
        <Navbar.Brand href="#">Transifex React Internationalization</Navbar.Brand>
        <Navbar.Toggle aria-controls="basic-navbar-nav" />
        <Navbar.Collapse id="basic-navbar-nav">
          <Nav className="ms-auto">
            <NavDropdown title="Language" id="basic-nav-dropdown">
              <NavDropdown.Item href="#">English</NavDropdown.Item>
              <NavDropdown.Item href="#">Arabic</NavDropdown.Item>
            </NavDropdown>
          </Nav>
        </Navbar.Collapse>
      </Container>
    </Navbar>
  );
}
export default Navigation;

Finally, replace the content of src/App.js with the following:

import React from 'react';
import { Container } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import Greeting from './components/Greeting';
import Navigation from './components/Navigation';
import Text from './components/Text';

function App() {

  return (
    <>
      <Navigation />
      <Container>
        <Greeting />
        <Text />
      </Container>
    </>
  );
}
export default App;

Run the Website

In your terminal, run the following command to run the website:

npm start

This will open the website in your browser and you can see all the components you just created.

How to Internationalize (i18n) a React App with Transifex Native

Localize Website

At the moment, the website is all in English and you can’t switch between languages or see any translations. You’ll now localize the website using your Transifex account.

Initialize Transifex

The first step is to initialize Transifex Native on the website. To do that, add the following import in src/App.js:

import { tx } from '@transifex/native';

Then, before the function App add the following code to initialize Transifex Native:

tx.init({
  token: process.env.REACT_APP_TRANSIFEX_TOKEN,
});

As you can see, you can use the init method of tx that is imported from the core Transifex Native library. You need to pass it the token that you copied earlier from your Transifex Native credentials. We pass it as a React environment variable.

To add the environment variable, create .env in the root of your React app with the following:

REACT_APP_TRANSIFEX_TOKEN=

Where the value is the API token that you copied earlier.

Add Translatable Strings

Now, you can make any string translatable. To do that, the Transifex Native React SDK has a component T that you can use to indicate that a text is translatable.

Open src/components/Greeting.js and add the import for T at the beginning of the file:

import { T } from '@transifex/react';

Then, replace “Hello” with the following:

<T _str="Hello" />

As you can see, the component T accepts a prop _str with the text that can be translated.

T can also accept the following props:

  1. _context: The context of the string.
  2. _key: custom key string
  3. _comment: comments from the developer about the string
  4. _charlimit: set a character limit for the translator to adhere to
  5. _tags: tags separated by commas

Similarly, open src/components/Text.js and add the following import at the beginning of the file:

import { T } from '@transifex/react';

Then, replace "Thank you for visiting our website." with the following:

<T _str="Thank you for visiting our website." />

Push Translation Strings

You just added 2 translatable strings. The next step is to push these strings to your Transifex Native project so they can be viewed on the project dashboard.

In package.json add the following new script:

"scripts": {
  ...,
  "push-translation": "txjs-cli push src --token=<TOKEN> --secret=<SECRET>"
}

Make sure to replace the <TOKEN> with your API token and <SECRET> with your API secret.

Using the CLI library that you installed earlier you can push translations to the Transifex Native project using the push command. The push command takes the directory it should look inside for translatable strings as a parameter. It also needs the token and secret you copied earlier.

Now, in your terminal, run the following command:

npm run push-translation

After this is run successfully, you’ll see that 2 string resources have been created. If you open the Resources page on your Transifex Native project, you should see that there are 2 strings that need a translation.

How to Internationalize (i18n) a React App with Transifex Native

If you click on the Translate button at the top right, you’ll be taken into a new page where you can select the language to translate the strings to. Select the language you want, and then you’ll be able to add the translations for each string using the easy-to-use interface.

How to Internationalize (i18n) a React App with Transifex Native

Change Languages

Ok, so, now you added the translations, but you need to be able to switch between languages on your website to see this change in action.

The Transifex Native React SDK has the hook useLanguages that allows you to retrieve the available languages in your project. You can use that to display the languages and allow the user to switch between them. To change languages, you can use the setCurrentLocale method from the core native library.

Alternatively, you can use the [LanguagePicker](https://docs.transifex.com/javascript-sdk/localize-react-applications#languagepicker-component) component 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.

Open src/components/Navigation.js and add the following imports at the beginning of the file:

import { tx } from '@transifex/native';
import { useLanguages } from '@transifex/react';

Then, inside the Navigation function create a new languages variable:

const languages = useLanguages();

Then, replace the elements nested inside NavDropdown with the following:

{languages.map(({code, name}) => (
  <NavDropdown.Item key={code} href="#" onClick={() => tx.setCurrentLocale(code)}>{name}</NavDropdown.Item>
))}

This will loop over the languages variable. Each language inside it will have code and name 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 tx.setCurrentLocale, which accepts the language code (or locale) as a parameter.

If you open your website now, you should see the languages when you click on the Languages dropdown.

How to Internationalize (i18n) a React App with Transifex Native

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.

How to Internationalize (i18n) a React App with Transifex Native

Translating More Text

Let’s now translate the “Language” string in the Navigation component.

In src/components/Navigation.js file add the import for T:

import { T, useLanguages } from '@transifex/react';

Then, change the title prop of NavDropdown to the following:

title={<T _str="Language" />}

The title prop can accept a component as a value.

You’ll need to push the new string to the Transifex Native project so run the push-translation command again:

npm run push-translation

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.

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.

To invalidate the cache, you can use the invalidate command of the CLI tool.

In package.json add the new script refresh-translation and make changes to the start script so that the translations are refreshed whenever the server for your website is started:

"scripts": {
    "start": "npm run refresh-translation && react-scripts start",
    ...,
    "refresh-translation": "txjs-cli invalidate --token=<TOKEN> --secret=<SECRET>"
  },

Just like before, make sure to replace <TOKEN> and <SECRET> with your credentials.

Now, run the start command again or run the refresh-translationcommand on its own. The “Language” string should now be translated when you switch languages.

How to Internationalize (i18n) a React App with Transifex Native

Changing Layout

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.

The Transifex Native React SDK has a useLocale 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.

In src/App.js add imports at the beginning of the file:

import React, { useEffect } from 'react';
import { useLocale } from '@transifex/react';

Then, inside the App function, add the following before the returnstatement:

const locale = useLocale();
useEffect(() => {
  if (locale) {
    document.body.style.direction = locale === 'en' ? 'ltr' : 'rtl';
  }
}, [locale]);

You first retrieve the locale using useLocale. Then, whenever locale is changed, you change the direction style property of the body of the page based on the locale.

Next, in src/components/Navbar.js add the necessary import for useLocale:

import { T, useLanguages, useLocale } from '@transifex/react';

Then, create the locale variable inside the Navigation function:

const locale = useLocale();

Finally, change the className prop of the Nav element to the following:

className={!locale || locale === 'en' ? "ms-auto" : "me-auto"}

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.

Now, open the website and switch to an RTL language. You should see that the layout has changed.

How to Internationalize (i18n) a React App with Transifex Native

If you try to switch back to English, the layout will go back to the way it was.

Benefits of Transifex Native React SDK

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.

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.

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 SDKs for all these types of projects, and as it also has REST APIs 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.

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 React Context. This concept can seem complex to some, so to be able to easily retrieve the current locale is also a nice plus.

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.

Conclusion

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.

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. This is something that you can solve with Transifex. You can also crowdsource your translation if you have an open-source project and need the help of the community.

Be sure to check out Transifex’s React SDK documentation to see all the functionalities it provides and see all the cool things you can do with this SDK and platform as a whole.

]]>
<![CDATA[How to Add Authentication with Google Authenticator in Node.js]]>https://blog.shahednasser.com/how-to-add-authentication-with-google-authenticator-in-node-js/Ghost__Post__61eaec366e875c05c40940deTue, 25 Jan 2022 10:12:09 GMT

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.

One form of 2FA is using authenticator apps like Google's Authenticator. 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.

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.

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.

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.

You can find the code for this tutorial in this GitHub repository.

Prerequisites

You need Node.js installed on your machine to be able to follow along with this tutorial.

Project Setup

Start by creating a directory for our project and changing to it:

mkdir 2fa-tutorial
cd 2fa-tutorial

Then, initialize the project with NPM:

npm init -y

The -y option will fill the fields of package.json with default values.

Next, install the dependencies that you'll use for this tutorial:

npm i express ejs body-parser express-session express-jwt jsonwebtoken sqlite3 otplib qrcode nodemon

Here's what each dependency is for:

  1. express: To create a server
  2. ejs: View engine to be used to create pages
  3. body-parser: To parse body parameters from the request
  4. express-session: Manage session in the server
  5. express-jwt and jsonwebtoken: Create JSON Web Token (JWT) and add middleware to ensure that a user is authenticated
  6. sqlite3: To interact with an SQLite database
  7. otplib: To generate the secret which will be used to add 2FA with the authenticator app
  8. qrcode: To generate the QRCode that should be scanned by the authenticator app
  9. nodemon: To restart the server whenever there are changes

Out of all these dependencies, the important ones for 2FA are otplib and qrcode. The rest are more related to setting up the server and website.

Create Server

Create index.js in the root directory with the following content:

const express = require('express')
const sqlite3 = require('sqlite3')
const session = require('express-session')
const { authenticator } = require('otplib')
const QRCode = require('qrcode')
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
const bodyParser = require('body-parser')
const app = express()
const port = 3000

app.set('view engine', 'ejs')

app.use(session({
  secret: 'supersecret',
}))


app.use(bodyParser.urlencoded({ extended: false }))

//create database with tables if it doesn't exist
const db = new sqlite3.Database('db.sqlite')
db.serialize(() => {
  db.run('CREATE TABLE IF NOT EXISTS `users` (`user_id` INTEGER PRIMARY KEY AUTOINCREMENT, `email` VARCHAR(255) NOT NULL, `secret` varchar(255) NOT NULL)')
})
db.close()

app.listen(port, () => {
  console.log(`2FA Node app listening at http://localhost:${port}`)
})

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 users table if they don't exist. The users table, for simplicity, will only have the columns user_id, email and secret.

Create Sign Up Page

The home page of the website will be the signup page.

In index.js add the route for / as follows:

app.get('/', (req, res) => {
  res.render('signup.ejs')
})

This will only render the EJS view signup.ejs which you'll create next.

Create views/signup.ejs with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sign Up</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
  <div class="container mx-auto mt-4">
    <h1>Sign Up</h1>
    <form action="/sign-up" method="POST">
      <div class="mb-3">
        <label for="email" class="form-label">Email</label>
        <input type="email" class="form-control" id="email" name="email">
      </div>
      <button type="submit" class="btn btn-primary">Sign Up</button>
    </form>
    <p class="mt-4">
      Have an account? <a href="/login">Login</a>
    </p>
  </div>
</body>
</html>

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.

Back in index.js, create the POST route to handle the registration:

app.post('/sign-up', (req, res) => {
  const email = req.body.email,
    secret = authenticator.generateSecret()

  const db = new sqlite3.Database('db.sqlite')
  db.serialize(() => {
    db.run('INSERT INTO `users`(`email`, `secret`) VALUES (?, ?)',
      [email, secret],
      (err) => {
        if (err) {
          throw err
        }

        //generate qr and put it in session
        QRCode.toDataURL(authenticator.keyuri(email, '2FA Node App', secret), (err, url) => {
          if (err) {
            throw err
          }

          req.session.qr = url
          req.session.email = email
          res.redirect('/sign-up-2fa')
        })
      })
  })
})

You first retrieve the email from the body and you create a secret using authenticator.generateSecret. authenticator is from the otplib library. generateSecret generates a base32 encoded hex secret that will be used to add your app into an authenticator app like Google Authenticator.

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 qrcode library. The QRCode content should be a Key Uri of the following format:

otpauth://{type}/{app}:{accountName}?secret={secret}{query}

Where {type} is either totp for TOTP or hotp for HMAC-based one-time password (HOTP). For this tutorial, we're going with the default type for authenticator in otplib which is totp.

{app} is the name of the app this 2FA is for. It will appear in the user's app after they scan the code. {accountName} is their email in the app.

{secret} is the secret you generated earlier. You can also pass additional query parameters in the place of {query} 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 &digits=8.

authenticator has the method keyuri which accepts an email (accountName), the app's name (app), and the secret (secret) as parameters. You can, instead, pass an object of options, which will allow you to add customizations like the digits query parameter.

The qrcode library has the method toDataURL. 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.

If everything is successful, the user will be redirected to sign-up-2fa where they add authentication with their authenticator app.

Create Add Authentication Page

In index.js, add the new route sign-up-2fa:

app.get('/sign-up-2fa', (req, res) => {
  if (!req.session.qr) {
    return res.redirect('/')
  }

  return res.render('signup-2fa.ejs', { qr: req.session.qr })
})

If qr isn't in the session, then you redirect the user to the home page. Otherwise, you render the signup-2fa.ejs view passing it the QRCode data URL.

Create views/signup-2fa.ejs with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Sign Up - Set 2FA</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
  <div class="container mx-auto mt-4">
    <h1>Sign Up - Set 2FA</h1>
    <form action="/sign-up-2fa" method="POST">
      <p>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.</p>
      <img src="<%= qr %>" class="img-fluid" />
      <div class="mb-3">
        <label for="code" class="form-label">2FA Code</label>
        <input type="text" class="form-control" id="code" name="code">
      </div>
      <button type="submit" class="btn btn-primary">Submit</button>
    </form>
  </div>
</body>
</html>

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.

Now, you'll add the /sign-up-2fa POST route in index.js:

app.post('/sign-up-2fa', (req, res) => {
  if (!req.session.email) {
    return res.redirect('/')
  }

  const email = req.session.email,
    code = req.body.code

  return verifyLogin(email, code, req, res, '/sign-up-2fa')
})

This will retrieve the user's email and code from the session and request body respectively. Then, it will call the verifyLogin function which you'll create next:

function verifyLogin (email, code, req, res, failUrl) {
  //load user by email
  const db = new sqlite3.Database('db.sqlite')
  db.serialize(() => {
    db.get('SELECT secret FROM users WHERE email = ?', [email], (err, row) => {
      if (err) {
        throw err
      }

      if (!row) {
        return res.redirect('/')
      }

      if (!authenticator.check(code, row.secret)) {
        //redirect back
        return res.redirect(failUrl)
      }

      //correct, add jwt to session
      req.session.qr = null
      req.session.email = null
      req.session.token = jwt.sign(email, 'supersecret')

      //redirect to "private" page
      return res.redirect('/private')
    })
  })
}

This function, first, retrieves the user by their email. Then, the code is validated with the secret in the database using authenticator.check method. This method takes the code as the first parameter and the secret as the second parameter. It returns a boolean value.

If the check method returns true, it means that you can authenticate the user. You set the token in the session to a JWT created by the jwt library. Then, you redirect the user to the private page that you'll create later.

Create Log In Page

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.

In index.js add the /login route:

app.get('/login', (req, res) => {
  return res.render('login.ejs')
})

This will just render the login.ejs view.

Create views/login.ejs with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Log In</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
  <div class="container mx-auto mt-4">
    <h1>Log In</h1>
    <form action="/login" method="POST">
      <div class="mb-3">
        <label for="email" class="form-label">Email</label>
        <input type="email" class="form-control" id="email" name="email">
      </div>
      <div class="mb-3">
        <label for="code" class="form-label">Code</label>
        <input type="code" class="form-control" id="code" name="code">
      </div>
      <button type="submit" class="btn btn-primary">Log In</button>
    </form>
    <p class="mt-4">
      Don't have an account? <a href="/">Sign Up</a>
    </p>
  </div>
</body>
</html>

As mentioned, this page shows a form with 2 inputs: Email and Code. This form then sends the form data to the /login POST route.

In index.js add the POST route for login:

app.post('/login', (req, res) => {
  //verify login
  const email = req.body.email,
    code = req.body.code

  return verifyLogin(email, code, req, res, '/login')
})

This function has similar functionality as the sign-up-2fa. It retrieves the email and code from the body parameters then calls verifyLogin to either log in the user or redirect them back to the form.

Create Private Page

Now, you'll create a private page, which is only accessible by logged-in users.

In index.js add the route private:

const jwtMiddleware = expressJWT({
  secret: 'supersecret',
  algorithms: ['HS256'],
  getToken: (req) => {
    return req.session.token
  }
})

app.get('/private', jwtMiddleware, (req, res) => {
  return res.render('private.ejs', {email: req.user})
})

This route uses the jwtMiddleware, which is created using the express-jwt 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 private.ejs view is rendered.

Create views/private.ejs with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Private</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
  <div class="container mx-auto mt-4">
    <h1>Hello, <%= email %></h1>
    <a href="/logout">Log Out</a>
  </div>
</body>
</html>

This will only show a greeting to the user with their email and a log-out button.

Create Log Out Route

Finally, you just need to add a log-out route.

In index.js, add the logout route:

app.get('/logout', jwtMiddleware, (req, res) => {
  req.session.destroy()
  return res.redirect('/')
})

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.

Test it Out

Let's test it all out. First, run the server:

npm start

This will create the SQLite database db.sqlite and  start the server at localhost:3000. Open it in your browser. You'll see the signup form.

How to Add Authentication with Google Authenticator in Node.js

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.

How to Add Authentication with Google Authenticator in Node.js

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.

How to Add Authentication with Google Authenticator in Node.js

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.

How to Add Authentication with Google Authenticator in Node.js

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.

Conclusion

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.

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.

]]>
<![CDATA[How to Track the Rank of Keywords in Google SERPs using Python]]>https://blog.shahednasser.com/track-keywords-in-google-using-python/Ghost__Post__63404f3c4e918d05f3537ce0Fri, 07 Oct 2022 16:24:53 GMT

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.

So in this post, we will create a crawler that will keep you updated with your latest rank on any keyword you want to track.

We will create a web scraper to scrape google search results using python. I am assuming that you have already installed python on your computer. We will begin with coding the web scraper.

Let’s code

First, we need to install all the necessary libraries.

·        Requests

·        BeautifulSoup

Create a folder and then install these libraries:

mkdir googlescraper
pip install requests
pip install beautifulsoup4

Then we will import these libraries into our file. You can name the file googlescraper.py:

import requests
from bs4 import BeautifulSoup

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.

Google URL structure — https://www.google.com/search?q={any keyword or phrase}

For this blog post, our target keyword will be “scrape prices” and we have to find the rank of the domain christian-schou.dk at this keyword.

So, our target URL will be this.

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 jGGQ5e and then into yuRUbf. After this, we have to find a tag inside class yuRUbf and then get the value of href tag.

headers={‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',’referer’:’https://www.google.com'}
target_url=’https://www.google.com/search?q=scrape+prices'
resp = requests.get(target_url, headers=headers)
print(resp.status_code)

Here we have declared some headers like User-Agent and a Referer to act like a standard browser and not as a crawler.

Then we declared our target URL and finally made the GET request using the requests library. Once we run this code you should see 200 on your terminal.

Now, our target is to find our domain. Let’s find it using BS4.

soup=BeautifulSoup(resp.text,’html.parser’)
results = soup.find_all(“div”,{class:”jGGQ5e”})

We have used html.parser inside the BS4 library to create a tree of our HTML code. results array, you will get the HTML code of all the top 10 results.

In this list, we have to search our links one by one. For that, we are going to use for loop.

from urllib.parse import urlparse
for x in range(0,len(results)):
   domain=urlparse(results[x].find("div",{"class":"yuRUbf"}).find("a").get("href")).netloc
  
   if(domain == 'blog.christian-schou.dk'):
       found=True
       position=x+1
       break;
   else:
       found=False
if(found==True):
   print("Found at position", position)
else:
   print("not found in top", len(results))

We have used urlparse library to parse out the domain from the link. Then we are trying to match our domain with the domain we extracted.

If it matches we will get the position and if it does not match then it will print not found.

Let us run this code and let’s see what we get.

Well, the request was successful as I can see a 200 but we could find this domain in the top 10 results.

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.

Google URL will become https://www.google.com/search?q=scrape+prices&num=20

Run the program again and check whether you see this domain or not.

This time I found the domain in the 18th position on Google search results.

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.

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.

Going forward you can also create an SEO tool just like Ahref and Semrush or you can create a lead generation tool like Snov.

Complete Code

import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse
headers={‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',’referer’:’https://www.google.com'}
target_url=’https://www.google.com/search?q=scrape+prices&num=20'
resp = requests.get(target_url, headers=headers)
print(resp.status_code)
soup=BeautifulSoup(resp.text,’html.parser’)
results = soup.find_all(“div”,{class:”jGGQ5e”})
# print(results)
for x in range(0,len(results)):
domain=urlparse(results[x].find(“div”,{class:”yuRUbf”}).find(“a”).get(“href”)).netloc
 
if(domain == ‘blog.christian-schou.dk’):
  found=True
  position=x+1
  break;
else:
  found=False
if(found==True):
print(“Found at position”, position)
else:
print(not found in top”, len(results))

Running the code every 24 hours

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.

For that you can mail yourself the current position every morning, this will keep you updated.We will use schedule library to implement this task.

Complete Code

import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse
import schedule
import time
def tracker():
headers={‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',’referer’:’https://www.google.com'}
target_url=’https://www.google.com/search?q=scrape+prices&num=20'
resp = requests.get(target_url, headers=headers)
print(resp.status_code)
soup=BeautifulSoup(resp.text,’html.parser’)
results = soup.find_all(“div”,{class:”jGGQ5e”})
# print(results)
for x in range(0,len(results)):
 domain=urlparse(results[x].find(“div”,{class:”yuRUbf”}).find(“a”).get(“href”)).netloc
if(domain == ‘blog.christian-schou.dk’):
 found=True
 position=x+1
 break;
else:
 found=False
 position=x+1
if(found==True):
print(“Found at position”, position)
else:
print(not found in top “+ str(position)+ “ results”)
if __name__ == “__main__”:
schedule.every(5).seconds.do(tracker)
while True:
 schedule.run_pending()

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.

Now, to run it every day or after every 24 hours you can use:

schedule.every().day.at("12:00").do(job)

Now, let us mail ourselves these results to keep us updated with the latest position on google. For this task, we will use smtplib library.

Mail

import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse
import schedule
import time
import smtplib, ssl
def mail(position):
attackMsg = position
server = smtplib.SMTP(‘smtp.gmail.com’, 587)
server.ehlo()
server.starttls()
server.login(from@gmail.com”, “xxxx”)
SUBJECT = “Position Alert”
message = ‘From: from@gmail.com \nSubject: {}\n\n{}.format(SUBJECT, attackMsg)
server.sendmail(from@gmail.com”, ‘send_to@gmail.com’, message)
 
server.quit()
return True
def tracker():
headers={‘User-Agent’:’Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',’referer’:’https://www.google.com'}
target_url=’https://www.google.com/search?q=scrape+prices&num=20'
resp = requests.get(target_url, headers=headers)
print(resp.status_code)
soup=BeautifulSoup(resp.text,’html.parser’)
results = soup.find_all(“div”,{class:”jGGQ5e”})
# print(results)
for x in range(0,len(results)):
 domain=urlparse(results[x].find(“div”,{class:”yuRUbf”}).find(“a”).get(“href”)).netloc
if(domain == ‘blog.christian-schou.dk’):
 found=True
 position=x+1
 break;
else:
 found=False
 position=x+1
if(found==True):
message=”Found at position “+ str(position)
mail(message)
else:
message=not found in top “+ str(position)+ “ results”
mail(message)
if __name__ == “__main__”:
schedule.every().day.at("12:00").do(job)
while True:
 schedule.run_pending()

In the mail function, we are making a login attempt to our Gmail account with the password.

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.

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 nohup.

Nohup will ignore the hangup signal and will keep running your script even if you stop it.

I leave this task to you as homework in a hope that you will learn something new and unique.

Conclusion

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.

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.

]]>
<![CDATA[What are Prime Numbers?]]>https://blog.shahednasser.com/what-are-prime-numbers/Ghost__Post__62dc5a284e918d05f3537766Sat, 23 Jul 2022 20:32:09 GMT

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.

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!

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".

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.

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.

Mathematicians will never stop trying to find a way to test a number if it is prime or not, could it possible?

]]>
<![CDATA[What is Representation Theory?]]>https://blog.shahednasser.com/what-is-representation-theory/Ghost__Post__625dc17339840e1ac28750f8Mon, 18 Apr 2022 19:54:03 GMT

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.

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.

The importance of representation theory is that abstract problems are reduced to problems in linear algebra which is a well-known theory in mathematics.

An important branch of representation theory is "group
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.

More exactly, a "representation" of group G means a homomorphism mapping from G to the automorphism group of the object.

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.

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.

]]>
<![CDATA[Will Apple Release Security Updates for the iOS 14 after the iOS 15 Launch?]]>https://blog.shahednasser.com/will-apple-release-security-updates-for-the-ios-14-after-the-ios-15-launch/Ghost__Post__6200da7660a9ab05cc5e6a97Mon, 07 Feb 2022 10:28:28 GMT

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.

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 iPhone repair service for quick and efficient solutions.

What do We Know about iOS 14 Security Updates?

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.

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.

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.

Latest Security Features You Find in iOS 14

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.

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

Stronger Wi-Fi Security

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.

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.

This feature protects your device when it is connected to a public Wi-Fi network.

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.

Alerts when Apps Monitor Your Clipboard

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.

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.

Permission Required for App Tracking

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.

Advanced Camera and Microphone Usage Alerts

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.

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.

What do You Get by Updating iOS 15?

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:

New FaceTime Features

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.

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.

Apple Wallet Enhancements

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.

Health App Additions

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.

Live Text and Visual Lookup

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.

Should You Update to iOS 15?

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.

Also read: First Impression On The Latest iPhone

]]>
<![CDATA[React useMemo vs useCallback: When To Use?]]>https://blog.shahednasser.com/react-usememo-vs-usecallback-when-to-use/Ghost__Post__6202b0f410971d0605f2b448Sun, 06 Feb 2022 18:14:00 GMT

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!

In this article, we’ll explore React useMemo vs useCallback and when to use useCallback and useMemo.

Understanding the Terms: useMemo vs useCallback vs useEffect

useCallback, useMemo, and useEffect are used to optimize the performance of React-based applications as components are rerendered.

useCallback

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.

useMemo

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.

useEffect

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.

Using useCallback vs useMemo in Practice

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.

When you are wrapping a component with React.Memo(), 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.

useMemo and useCallback Difference

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 React.Memo() 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.

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.

When NOT to use useMemo and useCallback

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.

Conclusion

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!

]]>
<![CDATA[What to Expect from Digital Transformation in Automotive in 2022?]]>https://blog.shahednasser.com/what-to-expect-from-digital-transformation-in-automotive-in-2022/Ghost__Post__61f7d5e360a9ab05cc5e687fMon, 31 Jan 2022 12:30:50 GMT

Digital transformation is the next big disruptor in the digital automotive 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.

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.

How will the automotive industry's digital transformation impact us?

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.

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.

Is the automotive industry digital transformation necessary?

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.

Automobile manufacturers face digitization challenges

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:

Investment

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.

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.

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 $600 on self-driving vehicle technology.

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 $600 for an alternative-fuel car. These concerns persist, although proponents of these technological advancements have a dubious client desire for technology.

Fear of change

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.

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.

Customer-centricity

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.

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.

Examples of digital transformation in the automotive industry

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:

  • Mercedes-Benz and Circular collaborated to build an environmental monitoring system for the supply chain of battery cell manufacturers.
  • 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.
  • 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.
  • 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.
  • 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.

The automobile industry's evolution and its impact on customer service

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.

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.

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.

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.

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.

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.

To summarize

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.

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.

]]>
<![CDATA[Language-Learning App Development Features in 2022]]>https://blog.shahednasser.com/language-learning-app-development-features-in-2022/Ghost__Post__61f7d45460a9ab05cc5e686aMon, 31 Jan 2022 12:27:17 GMT

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.

To solve these challenges, entrepreneurs have ventured into language learning app development. But to do this, they need to learn how to create a language learning app to capitalize on the opportunity.

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.

This article will reveal the benefits and the features of language learning apps that you will need to create an app loved by users.

Benefits of Language Learning Apps

Convenience

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.

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.

Multiple Languages

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.

You can learn more than one language simultaneously on the same app while keeping track of your level.

Custom Levels

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.

Progress Tracker

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.

Once you have revised and feel confident, you can move to the next level.

Features for Language Learning App Development

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.

Registration

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.

Dashboard

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.

Users should track achievements such as rewards, bonuses, gems, and crowns that they can redeem within the app for prizes.

Illustration

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.

Online Community

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.

Online communities encourage users through sharing in the progress and achievements of others through the language learning app.

Health

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.

Conclusion

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.

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.

]]>
<![CDATA[Can Java Be Used for eCommerce?]]>https://blog.shahednasser.com/can-java-be-used-for-ecommerce/Ghost__Post__61e977bb6e875c05c40940bbMon, 24 Jan 2022 13:00:26 GMT

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.

Let's take a closer look at Java and see what it has to offer!

Still Going Strong After 26 Years

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 coding for beginners.

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.

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.

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.

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.

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.

Some Limitations of Java

Although Java makes sense for a wide swathe of businesses, it does have some limitations.

Firstly, Java has high memory and processing requirements, which can lead to increased hardware costs.

Java also doesn't give you control over garbage collection, which can lead to performance bottlenecks that need to be addressed.

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.

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.

Does Java Make Sense for Your eCommerce Business?

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?

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.

However, as we noted above, Java's limitations might make it a poor choice for some businesses.

Let's break down some of the key factors you have to consider before using Java to develop your eCommerce application:

Memory and processing requirements

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.

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 JavaScript, which is more of a lighter scripting language.

Garbage collection

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.

Access to expert programmers

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.

If you live or work near areas with a high concentration of Java developers, you're in luck. The benefits of having Java developers 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.

Conclusion

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.

]]>
<![CDATA[Create PDF in Laravel Tutorial]]>https://blog.shahednasser.com/create-pdf-in-laravel-tutorial/Ghost__Post__61e1abbe61dbd80628bf9c3cWed, 19 Jan 2022 08:48:05 GMT

Laravel is one of the most popular web development frameworks. It allows you to create fast, modern, and scalable websites for almost every use case.

In this tutorial, you'll learn how to create PDF files using Laravel and mPDF. 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.

You can find the full code for the tutorial at this GitHub repository.

Prerequisites

To follow along with this tutorial, you need to have PHP 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.

You also need to have Composer installed.

Project Setup

In this section, you'll set up a Laravel project. Open your terminal and run the following command:

composer create-project laravel/laravel laravel-pdf-tutorial

This will create the directory laravel-pdf-tutorial with the Laravel installation inside.

Once it's done, change to that directory and install mPDF to be used later:

composer require mpdf/mpdf

Create Page

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.

Create the file resources/views/home.blade.php with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>PDF Maker</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" 
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
  <script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script>
  <script>
    tinymce.init({
      selector: '.editor',
      toolbar: 
        'styleselect | alignleft aligncenter alignright | bold italic underline strikethrough | image | bullist numlist | table',
      plugins: 'image lists table',
      automatic_uploads: true,
      file_picker_types: 'image',
      file_picker_callback: function (cb, value, meta) {
        var input = document.createElement('input');
        input.setAttribute('type', 'file');
        input.setAttribute('accept', 'image/*');

        input.onchange = function () {
          var file = this.files[0];

          var reader = new FileReader();
          reader.onload = function () {
            var id = 'blobid' + (new Date()).getTime();
            var blobCache =  tinymce.activeEditor.editorUpload.blobCache;
            var base64 = reader.result.split(',')[1];
            var blobInfo = blobCache.create(id, file, base64);
            blobCache.add(blobInfo);
            cb(blobInfo.blobUri(), { title: file.name });
          };
          reader.readAsDataURL(file);
        };

        input.click();
      },
    });
  </script>
</head>
<body>
  <div class="container my-4 mx-auto">
    <form action="#" method="POST">
      @csrf
      <h1>PDF Maker</h1>
      <h2>Configurations</h2>
      <div class="mb-3">
        <label for="name" class="form-label">PDF Name</label>
        <input type="text" class="form-control" id="name" name="name" />
      </div>
      <div class="mb-3">
        <label for="header" class="form-label">Header</label>
        <textarea name="header" id="header" class="editor"></textarea>
      </div>
      <div class="mb-3">
        <label for="footer" class="form-label">Footer</label>
        <div id="footerHelp" class="form-text">You can use {PAGENO} to add page numbering to all pages</div>
        <textarea name="footer" id="footer" class="editor"></textarea>
      </div>
      <div class="form-check mb-3">
        <input class="form-check-input" type="checkbox" id="show_toc" name="show_toc">
        <label class="form-check-label" for="show_toc">
          Show Table of Content?
        </label>
      </div>
      <h2>Content</h2>
      <textarea name="content" id="content" class="editor"></textarea>
      <div class="text-center">
        <button type="button" class="btn btn-primary">Create</button>
      </div>
    </form>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body>
</html>

In this code, we show a form with configurations and a text editor for the content. We use Bootstrap for easy styling, and TinyMCE to easily insert an editor in our form. With TinyMCE, we also add an image picker based on this example from their documentation.

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.

Next, in routes/web.php change the route for the home page to the following:

Route::get('/', function () {
    return view('home');
});

Now, run the server:

php artisan serve

If you open the website now at localhost:8000 (by default), you'll see the form we just created.

Create PDF in Laravel Tutorial
PDF Maker Home Page

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 Tiny Cloud, or by downloading and self-hosting the TinyMCE library.

Notice that for the footer, we add a note that to add a page number to all pages we can use the placeholder {PAGENO}. This can be added to the header or footer.

Create PDF

In this section, you'll create the controller that will handle the form submission and create the PDF.

In your terminal, run the following command:

php artisan make:controller PdfController

Then, open the controller at app/Http/Controllers/PdfController.php and place the following method inside the class:

public function createPdf (Request $request) {
        //validate request
        Validator::validate($request->all(), [
            'name' => 'required|string|min:1',
            'content' => 'required|string|min:1'
        ]);

        //create PDF
        $mpdf = new Mpdf();

        $header = trim($request->get('header', ''));
        $footer = trim($request->get('footer', ''));

        if (strlen($header)) {
            $mpdf->SetHTMLHeader($header);
        }

        if (strlen($footer)) {
            $mpdf->SetHTMLFooter($footer);
        }

        if ($request->get('show_toc')) {
            $mpdf->h2toc = array(
                'H1' => 0,
                'H2' => 1,
                'H3' => 2,
                'H4' => 3,
                'H5' => 4,
                'H6' => 5
            );
            $mpdf->TOCpagebreak();
        }

        //write content
        $mpdf->WriteHTML($request->get('content'));

        //return the PDF for download
        return $mpdf->Output($request->get('name') . '.pdf', Destination::DOWNLOAD);
    }

Make sure to also add the necessary imports at the beginning of the file:

use Illuminate\Support\Facades\Validator;
use Mpdf\Mpdf;
use Mpdf\Output\Destination;

First, you validate the request using Laravel's Validate Facade. You can learn more about Laravel's Validation in this tutorial.

After validating the request parameters, you create a new instance of Mpdf. You can pass a lot of configurations to mPDF's constructor which allows you to set things like the font used or the text direction.

Next, you retrieve the values for Header and Footer entered by the user. If there are any entered, you set the Header with SetHTMLHeader and Footer with SetHTMLFooter. This will set the header and footer on all pages.

Then, you check if show_toc was checked. If it was, you add a Table of Content at the beginning of the PDF using TOCpagebreak. You also use the mPDF instance's h2toc parameter to define the hierarchy that should be used in the table of content. This makes it easier for Mpdf to generate the table of content from the PDF's content.

Next, you set the content of the PDF using WriteHTML. You will write the content 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.

Finally, you return the PDF for download using the Output method. This method receives as a first parameter the file name, and as a second parameter the return type. Its values can be I for inline (default behavior), D for download which will force download in the browser, F for file which should be used when storing the created file, and S for String Return which should be used when the PDF should be returned as a string.

In this case, you use D which will create the PDF and trigger the download automatically.

Now that the controller's method is finished, add the new route in routes/web.php:

Route::post('/create', [App\Http\Controllers\PdfController::class, 'createPdf']);

And change the action attribute of the form in resources/views/home.blade.php:

<form action="/create" method="POST">

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.

Bonus: Adding Stylesheets

mPDF allows you to add styling to your PDF document. You can pass it as a stylesheet as follows:

$stylesheet = "h1 { color: red; }";
$mpdf->WriteHTML($stylesheet,\Mpdf\HTMLParserMode::HEADER_CSS);

Conclusion

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 their documentation.

]]>
<![CDATA[Turn a Shopify backend open-source and headless in less than 10 minutes]]>https://dev.to/medusajs/turn-a-shopify-backend-open-source-and-headless-in-less-than-10-minutes-2g8mGhost__Post__61e43f6761dbd80628bf9c6eMon, 17 Jan 2022 09:00:00 GMT

In this article, I will show you how to migrate all of your products and collections from a Shopify backend to an open-source headless commerce backend, Medusa, in less than 10 minutes.

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.

Why Use Medusa

As Medusa 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:

  1. It gives you full flexibility to build any type of frontend(s) you may prefer - Medusa has starters in Next.js or Gatsby 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 here.
  2. 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.
  3. 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 here.
  4. 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.

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.

How to Migrate Data from Shopify to Medusa

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.

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 this tutorial on how you can set up and run Medusa.

In my case, I have 30 products in my Shopify store, each having many variants and attributes.

Turn a Shopify backend open-source and headless in less than 10 minutes
Turn a Shopify backend open-source and headless in less than 10 minutes

Create a Private Shopify App

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.

Open your store’s dashboard. Then, choose Apps from the sidebar. Then, scroll down and click on Manage private apps.

Turn a Shopify backend open-source and headless in less than 10 minutes

If you haven’t enabled private apps previously, you’ll be asked to enable them first. click on Enable private app development to enable it.

After you have enable private app development, you’ll be able to create a private app. Click on Create private app to get started.

Turn a Shopify backend open-source and headless in less than 10 minutes

You’ll then need to enter your app’s name and your email. Then, scroll down to the Admin API section and click on Show inactive Admin API permissions. Scroll down to Products and choose Read Access from the dropdown. Medusa only needs to read products and collections.

Turn a Shopify backend open-source and headless in less than 10 minutes

Scroll down to the end of the page and click the Save button. Then, click Create App in the pop-up that shows up.

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.

Add medusa-source-shopify to your Medusa store

You’ll now integrate the Shopify plugin into your Medusa server. To integrate the plugin, you need the following:

  1. The Shopify domain name and the password of the Shopify app you want to link to.
  2. PostgreSQL database used with your Medusa server.

At this point of the article, it’s assumed you have all of these requirements ready.

Open your terminal in your Medusa server installation and run the following command to install the plugin:

npm i medusa-source-shopify

Then, in .env add the following new variables:

SHOPIFY_DOMAIN=
SHOPIFY_PASSWORD=

Where SHOPIFY_DOMAIN is the subdomain name of your Shopify store (for example, my store is shahednasser.myshopify.com, so the value would be shahednasser), and SHOPIFY_PASSWORD is the password generated when you created the app earlier.

Then, open medusa-config.js and add a new entry into the plugins array:

    const plugins = [
      ...,
      {
        resolve: 'medusa-source-shopify',
        options: {
          domain: process.env.SHOPIFY_DOMAIN,
          password: process.env.SHOPIFY_PASSWORD
        }
      }
    ];

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.

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:

npm start

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.

Your products and collections will be imported with pricing, variants, and all the attributes and details you had in your Shopify store.

Turn a Shopify backend open-source and headless in less than 10 minutes

Why Migrate From Shopify to an Open Source backend

According to BuiltWith, 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.

Although Shopify has a lot of advantages that make businesses and developers gravitate towards it, it all comes at the expense of less ownership of the tech stack. 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.

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.

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.

Conclusion

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.

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.

Should you have any issues or questions related to Medusa, then feel free to reach out to the Medusa team via Discord.

]]>
<![CDATA[7 JavaScript Color Libraries and Which Should You Choose]]>https://blog.shahednasser.com/7-javascript-color-libraries-and-which-should-you-choose/Ghost__Post__61d3153061dbd80628bf9acdMon, 10 Jan 2022 09:31:04 GMT

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.

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.

color2k

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.

This library provides different useful methods including converting colors like toHex or toRgba, color manipulation like darken or mix, and more methods that allow you to parse colors.

This library is easy to use in your Node.js projects. All you need is to install it:

npm i color2k

Then import the methods you want to use:

import { mix } from color2k;

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.

When Should You Use color2k?

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.

chroma.js

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.

In addition, chroma.js provides methods like scale that allow you to represent a color scale between two or more colors. You can also retrieve a color scheme using the cubehelix method.

Using this library is easy as well. You first need to install it in your Node.js project:

npm install chroma-js

Then, import it where you need to use it:

import chroma from "chroma-js";

And you'll have access to all the methods you need.

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.

When Should You Use chroma.js?

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.

Color Thief

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.

To use it in your browser you can either download from the repository the files under dist. Alternatively, you can use their CDN.

After you include the script to the file, you just need to create a new instance to use:

const colorThief = new ColorThief();

To use it in Node, you just need to install it:

npm i --save colorthief

And then require it:

const ColorThief = require('colorthief')

The library exposes 2 methods. The first is getColor which allows you to retrieve the dominant color in an image. The second is getPalette which allows you to retrieve all the colors in an image.

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.

When Should You Use Color Thief?

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.

color

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 rgb(255, 255, 255).

color has a wide set of color getters like red which returns the red value of a color or hsl which retrieves the HSL value of a color. color also provides a wide set of manipulation methods like desaturate and lighten.

The installation and usage are easy. You can install color with NPM:

npm install color

Then, require it where you need to use it:

const Color = require('color');

and you'll have access to all its methods.

color's manipulation and interpolation methods are not as many as chroma.js, but it has a smaller size (7.6KB).

When Should You Use color?

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.

Random Color

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 hue, format, and luminosity to make the color generated not too random.

You can install this package from NPM:

npm install randomcolor

And require it where you need to use it:

var randomColor = require('randomcolor')

Alternatively, you can use it in your browser using their CDN.

This library exposes one function only which is the randomColor function. This function receives optionally an options object.

When Should You Use Random Color?

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.

ac-colors

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 randomOfTypeFormatted.

ac-colors can be used in the browser using their CDN.

Alternatively, you can install it with NPM:

npm install ac-colors

Then requiring it:

const Color = require("ac-colors");

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.

When Should You Use ac-colors?

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.

TinyColor

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 isLight. However, it still provides color manipulation functions like brighten and darken. On top of all of that, it allows you to generate color palettes and random colors.

As mentioned earlier, you can use TinyColor in the browser.

Alternatively, you can install it with NPM:

npm install tinycolor2

and require it where you need it:

var tinycolor = require("tinycolor2");

TinyColor is relatively small (5KB) with the number of functionalities it provides.

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.

When Should You Use TinyColor?

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.

It doesn't, however, provide a wide set of manipulation functionalities like chroma.js.

Conclusion

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.

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.

]]>
<![CDATA[CSS Grid Tutorial For Beginners]]>https://blog.shahednasser.com/css-grid-tutorial-for-beginners/Ghost__Post__61d2b40c61dbd80628bf99b1Wed, 05 Jan 2022 13:38:06 GMT

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.

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.

Why Use CSS Grid

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.

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.

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.

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.

Your First Grid

Let's say we have the following HTML:

<div class="container">
  <p class="red"></p>
  <p class="green"></p>
  <p class="blue"></p>
</div>

We want to make the div with the class container a grid where we can control the elements inside as explained earlier.

All we need to do is change the display property of the class container:

.container {
    display: grid;
}

This will make the element with the class container a grid element. If you test this out, you'll see that you can see nothing. The reason behind that is the p elements in the .container grid don't have any elements in them or width or height.

Add the following CSS:

.container p {
  width: 100px;
  height: 100px;
}

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.blue {
  background-color: blue;
}

This will set the width and height of the p elements to 100px. It will also give a different background color for each element.

If you check your grid now it should look something like this:

CSS Grid Tutorial For Beginners

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.

Instead of specifying the width and height of each element, you can also use grid-auto-rows and grid-auto-columns on the grid element to specify the default height and width of elements:

.container {
    ...
    grid-auto-rows: 100px;
    grid-auto-columns: 100px;
}

Elements Placements

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.

Columns

Let's say you want to place these 3 elements as just 3 items in a row. we can do that  using the grid-template-columns property.

This property takes an n number of values, where n is the number of columns you want in the grid and each value is the width of each column.

For example, if you want to have 3 columns in the grid each having their width as 100px you can use:

grid-template-columns: 100px 100px 100px;

This will divide the grid into 3 columns, and each column will be 100px.

Let's say you want the second column to be 200px:

grid-template-columns: 100px 200px 100px;

If you also don't have a specific value to apply you can use the value auto:

grid-template-columns: auto auto auto;

Alternatively, instead of repeating the values, you can use the repeat() function:

grid-template-columns: repeat(3, auto);

The repeat CSS function takes the first parameter the number of times an expression should be repeated, and the second parameter the statement to repeat.

Let's go back to our example, we'll place our elements in 3 columns, each having an automatic width.

Change the properties of .container to the following:

.container {
  display: grid;
  grid-template-columns: repeat(3, auto);
}

This will ensure the grid has 3 c0lumns with each having their width set to auto.

Next, remove the width property set on the p elements from earlier. It should only have height now:

.container p {
  height: 100px;
}

If you check the grid now, it should have 3 elements with equal widths next to each other.

CSS Grid Tutorial For Beginners

Gap Between Columns

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 grid-column-gap which takes the length of the gap between the columns as a value.

Let's say we want to add a gap of 5px between our columns. Add the following property to .container:

grid-column-gap: 5px;

This will add a 5px space between the grid columns.

CSS Grid Tutorial For Beginners

Placement in Columns

You can control the placement of items relative to columns using the grid-column-start and grid-column-end 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.

The value for grid-column-start and grid-column-end can be a number. In this case, it will specify the column to start at and the column to end before.

For example, if you want to specify that the .red element should start in the beginning and end before the 3rd column you use the following properties:

.red {
  background-color: red;
  grid-column-start: 1;
  grid-column-end: 3;
}

Now, the .red element will span 2 columns and the .blue element will be pushed to the row below.

CSS Grid Tutorial For Beginners

Alternatively, you can provide a value to grid-column-start and grid-column-end in the format span n, where n 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 n columns.

If we want to apply the same example, we can use the following properties for .red instead:

.red {
  background-color: red;
  grid-column-start: span 2;
}

This means the element should span 2 columns. This will result in the same layout as shown previously.

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:

.blue {
  background-color: blue;
  grid-column-start: 3;
}

Now, instead of the blue element just being shifted down outside of our control, we specify exactly where it should be:

CSS Grid Tutorial For Beginners

Rows

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.

To specify how many rows a grid has, you can use grid-template-rows. Similar to columns, the grid-template-rows takes n values, where n is the number of rows the grid will have and the value is the height of each row.

So, if you want to have 2 rows of 100px height you can use the following:

grid-template-rows: 100px 100px;

Alternatively, you can use the repeat function:

grid-template-rows: repeat(2, 100px);

This will create 2 rows each having 100px height.

Let's go back to our example. In this section, we want to have 2 columns and 2 rows. Change .container to the following:

.container {
  display: grid;
  grid-template-columns: repeat(2, auto);
  grid-template-rows: repeat(2, 100px);
  grid-column-gap: 5px;
}

This will create 2 columns of auto width and 2 rows of 100px height.

Next, reset the rest of the styles that we performed earlier:

.red {
  background-color: red;
}

.green {
  background-color: green;
}

.blue {
  background-color: blue;
}

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 grid-template-columns and grid-template-rows.

If you check your grid now you should have 2 items in one row and an item on the second.

CSS Grid Tutorial For Beginners

Gap Between Rows

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 grid-row-gap.

Let's say we want to add a 5px gap between rows. Add the following property to the .container class:

grid-row-gap: 5px;

This will add a 5px space between the rows in our grid.

CSS Grid Tutorial For Beginners

Placement in Rows

You can use the grid layout to control the placement of elements in rows. To do that, you can use the properties grid-row-start and grid-row-end.

The value of grid-row-start and grid-row-end can be a number. The value of grid-row-start will be the row the element should start on, and the value of grid-row-end will be the row the element should end before.

For example, to make sure that the red element spans 2 rows we can use the following properties:

.red {
  background-color: red;
  grid-row-start: 1;
  grid-row-end: 3;
}
CSS Grid Tutorial For Beginners

Alternatively, you can provide a value to the 2 properties in the format span n where n is the number of rows the element should span.

So, instead of the previous properties used, you can use the following to make sure the red element spans 2 rows:

.red {
  background-color: red;
  grid-row-start: span 2;
}

This will result in the same layout.

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.

Let's say you want to place the blue column in the first row. You can apply the following styling to do that:

.blue {
  background-color: blue;
  grid-row-start: 1;
}

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.

CSS Grid Tutorial For Beginners

To ensure that the blue item is on the right and the red element remains on the left, you can use the grid-column-start property:

.blue {
  background-color: blue;
  grid-row-start: 1;
  grid-column-start: 2;
}

This will retain the original placement of the red element, but the blue item will be in the first column.

CSS Grid Tutorial For Beginners

As you can see, you can use both properties for rows and columns to control many aspects of positioning and sizing of a grid.

Grid Areas

Instead of controlling a grid as columns and rows, you can control a grid as areas.

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.

First, start by giving the different element area names using the grid-area property:

.red {
  background-color: red;
  grid-area: Content;
}

.green {
  background-color: green;
  grid-area: Header;
}

.blue {
  background-color: blue;
  grid-area: Sidebar;
}

This gives the .red element the grid-area name Content, the .green element the grid-area name Header, and the .blue element the grid-area Sidebar.

Next, you use the grid-template-areas property on the grid container element to determine how these different areas should be distributed. The grid-template-areas takes as a value n string values, where n 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 Header element to take 2 columns in a row, you can use the value "Header Header" for the row.

In our example, we'll create 2 rows and 3 columns. The first row will just be the Header which will span the 3 columns, and the second row will be the Content which will span 2 columns and the Sidebar which will be just one column:

.container {
  display: grid;
  grid-template-areas: "Header Header Header" 
    "Content Content Sidebar";
  grid-row-gap: 5px;
  grid-column-gap: 5px;
  grid-auto-rows: 100px;
}

Since we want three columns in the grid, each string value in grid-template-areas should have 3 area names. The first string value is for the first row in the grid. As we just want the Header to occupy it the value will be the Header repeated 3 times.

The second string value is for the second row. We want the Content area to span 2 columns. So, in the string value we repeat the Content area twice then the Sidebar.

Notice that each string value is wrapped in " and string values are separated by a space.

We also add a gap between rows and columns using grid-row-gap and grid-column-gap. We also set the default row height to 100px using grid-auto-rows.

This will result in the following layout:

CSS Grid Tutorial For Beginners

fr Unit

To ensure that columns or rows in a grid use the same height or width, you can use the fr Unit. For example, to create 3 columns each having the same width:

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 100px;
}

Conclusion

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.

]]>
<![CDATA[How To Make A Smartwatch App Successfully?]]>https://blog.shahednasser.com/how-to-make-a-smartwatch-app-successfully/Ghost__Post__61d43a3661dbd80628bf9c24Tue, 04 Jan 2022 12:20:26 GMT

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.

Being Efficient

When you create a wear OS app, ensure that it is touch & glance 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.

Being Reasonable: How To Create An Android Wear App?

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.

Be Solicitous

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.

Designing An Economic App

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.

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 how to make a smartwatch app. In this article, we include a shorter version to continue reading.

Be Compatible

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.

Understanding The Differences

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.

Including The Notification Bar

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.

Wrapping Up

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.

]]>
<![CDATA[15 Free Programming Courses to Check Out in 2022]]>https://blog.shahednasser.com/15-free-programming-courses-to-check-out-in-2022/Ghost__Post__61d0ab0c61dbd80628bf9881Mon, 03 Jan 2022 07:51:09 GMT

Start learning online and land a job with the help of the community using Qvault.

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.

What's a better time to do that than with the beginning of a new year?

In this article, I'll share with you 15 programming courses that you can take to become a better programmer and learn new languages.

Git & GitHub Crash Course: Create a Repository From Scratch!

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.

Web Design for Web Developers: Build Beautiful Websites!

I previously wrote some tips 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.

Cybersecurity for Everyone

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.

Scripting and Programming Foundations

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.

Computer Programming for Everyone

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.

Programming for Everybody (Getting Started with Python)

This is a course by the University of Michigan 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.

Introduction to User Experience Design

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.

Linux Basics: The Command Line Interface

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.

Build a Quiz App with HTML, CSS, and JavaScript

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.

Introduction to Programming in C++

C++ is one of the top 5 popular languages 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 Advanced Programming in C++. This course is estimated to be 8 weeks long, at 6-8 hours per week.

Introduction to Game Development with Unity

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.

Introduction to Data Analytics with Python

This course is created by FutureLearn in collaboration with Tableau, 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 Pandas and Seaborn. This course is estimated to be 4 weeks long, at 3 hours per week.

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.

Introduction to Augmented Reality and ARCore

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.

Selenium Basics - Step by Step for Beginners

Selenium 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.

Conclusion

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!

]]>
<![CDATA[Generate 10 QR Code Types with React]]>https://blog.shahednasser.com/generate-10-qr-code-types-with-react/Ghost__Post__61c337f361dbd80628bf96b1Mon, 27 Dec 2021 11:07:36 GMT

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.

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.

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 this GitHub repository, and you can see it in live-action on this website.

Prerequisites

To follow along with this tutorial, you need to have both Node.js and NPM installed. NPM will be automatically installed when you install Node.js.

Setup Website

To create a new React website, run the following command in your terminal:

npx create-react-app react-qr-generator

After this command is done, change to the newly created directory:

cd react-qr-generator

Then, install React Bootstrap for easy styling:

npm install react-bootstrap bootstrap@5.1.3

Install QR Library

For this tutorial, you'll use the library react-qr-code. 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.

To install the library run the following command:

npm install react-qr-code

Home Page

Before you start creating all different types of QR Codes, you'll setup the main layout for the home page.

Change src/App.js to the following:

import { useState } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import Container from 'react-bootstrap/Container'
import Tab from 'react-bootstrap/Tab'
import Row from 'react-bootstrap/Row'
import Col from 'react-bootstrap/Col'
import Nav from 'react-bootstrap/Nav'
import QRCode from 'react-qr-code'

function App() {
  const [qrText, setQrText] = useState("");
  return (
      <Container className='mx-auto'>
      	<h1 className='my-4'>Qr Generator</h1>
      	{qrText.length > 0 && <QRCode value={qrText} />}
		<h4 className='my-3'>Choose the type of QRCode format</h4>
        <Tab.Container defaultActiveKey="text">
                <Row>
                  <Col sm={3}>
                    <Nav variant="pills" className="flex-column">
                    </Nav>
				  </Col>
                  <Col sm={9}>
                    <Tab.Content>
                    </Tab.Content>
				  </Col>
				</Row>
		<Tab.Container
      </Container>
  );
}

export default App;

Here, you create a custom vertical tab layout 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.

You also create the state variable qrText which will hold the text to generate a QR Code. When the qrText is not empty, the QRCode component from the library react-qr-code will show the QR Code for that text.

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 <Nav>, and the component will be added as a tab-pane nested inside <Tab.Content>.

The components will be placed inside a new directory components nested inside src, so make sure to create that directory.

Plain Text/URLs QR Codes

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.

You can actually create a QR Code for any kind of text. It doesn't need to be a URL.

In this section, you'll create a component that takes text or URL and generate the QR Code for it.

Create the file src/components/Text.js with the following content:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Text ({ setQrText }) {
  const [text, setText] = useState('');

  function handleSubmit (e) {
    e.preventDefault();

    setQrText(text);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Text or URL</Form.Label>
        <Form.Control type="text" value={text} onChange={(e) => setText(e.target.value)} />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Text

The Text component receives as a prop the function setQrText, 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.

Once the user enters the text or URL they want and clicks on the button "Generate", the text will be set with setQrText. This will change the value of qrText in the App component, which will show a QR Code for that text.

Next, add the link for this new tab in src/App.js nested in <Nav>:

<Nav>
    <Nav.Item>
 		<Nav.Link eventKey="text">Text and URLs</Nav.Link>
	</Nav.Item>
</Nav>

And add the new Tab pane nested in Tab.Content:

<Tab.Content>
    <Tab.Pane eventKey="text">
    	<Text setQrText={setQrText} />
    </Tab.Pane>
</Tab.Content>

Don't forget to import the new Text component at the top of the file:

import Text from './components/Text'

Let's test it out. Run the server with the following command:

npm start

This will run the server on localhost:3000 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.

Generate 10 QR Code Types with React

Try entering any text or URL. You should see a QR code generated at the top.

Generate 10 QR Code Types with React

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.

GeoLocation QR Codes

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.

The format of this QR Code's encoded value is as follows:

http://maps.google.com/maps?q={lat},{long}

Where {lat} is the latitude and {long} is the longitude of the location.

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.

Create src/components/Geolocation.js with the following content:

import { useState } from "react";
import { Button, Form, Spinner } from "react-bootstrap";

function Geolocation ({ setQrText }) {
  const [lat, setLat] = useState('');
  const [long, setLong] = useState('');
  const [locationLoading, setLocationLoading] = useState(false);

  function getCurrentLocation () {
    setLocationLoading(true);
    navigator.geolocation.getCurrentPosition((pos) => {
      setLat(pos.coords.latitude);
      setLong(pos.coords.longitude);
      setLocationLoading(false);
    }, (err) => {
      alert(err.message);
      setLocationLoading(false);
    }, {
      enableHighAccuracy: true
    });
  }

  function handleSubmit (e) {
    e.preventDefault();

    setQrText('http://maps.google.com/maps?q=' + lat + ','+ long);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Latitude</Form.Label>
        <Form.Control type="text" value={lat} onChange={(e) => setLat(e.target.value)} />
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Longitude</Form.Label>
        <Form.Control type="text" value={long} onChange={(e) => setLong(e.target.value)} />
      </Form.Group>
      <Button variant="secondary" type="button" className="me-2" disabled={locationLoading} onClick={getCurrentLocation}>
        {locationLoading && <Spinner animation="border" className="me-2 align-middle" />}
        Set Current Location
      </Button>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Geolocation

This component, similar to the previous one, receives the setQrText function as a prop. 3 state variables are defined. lat to hold the latitude value entered in the Latitude field, long to hold the longitude value entered in the Longitude field, and locationLoading to show a loading spinner when fetching the user's current location.

the getCurrentLocation is executed when the user clicks on Set Current Location. You first have to obtain the user's permission to get access to their location, then, when permitted, set the lat and long state variables based on the coordinates obtained.

Finally, when the form is submitted, the qrText is set using setQrText to the format shown before using lat and lang.

You just need to add the new tab in App.js just like you did in the previous section under <Nav>:

<Nav.Item>
    <Nav.Link eventKey="geo">GeoLocation</Nav.Link>
</Nav.Item>

And add the new component as a tab-pane under <Tab.Content>:

<Tab.Pane eventKey="geo">
    <Geolocation setQrText={setQrText} />
</Tab.Pane>

And, of course, import the component at the beginning of the file:

import Geolocation from './components/Geolocation'

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.

Generate 10 QR Code Types with React

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.

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.

Calendar QR Codes

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.

The text format for a Calendar QR Code is as follows:

BEGIN:VCALENDAR\nBEGIN:VEVENT\nDTSTART:{start-date}\nDTEND:{end-date}\nSUMMARY:{title}\nEND:VEVENT\nEND:VCALENDAR

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 YYYYMMDD with no separation between any of them.

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.

Create the file /src/components/Calendar.js with the following content:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Calendar ({ setQrText }) {
  const [title, setTitle] = useState('');
  const [dateStart, setDateStart] = useState('');
  const [dateEnd, setDateEnd] = useState('');


  function handleSubmit (e) {
    e.preventDefault();

    const dateStartFormatted = dateStart.replace(/-/g, "");
    const dateEndFormatted = dateEnd.replace(/-/g, "")

    setQrText(`BEGIN:VCALENDAR\nBEGIN:VEVENT\nDTSTART:${dateStartFormatted}\nDTEND:${dateEndFormatted}\nSUMMARY:${title}\nEND:VEVENT\nEND:VCALENDAR`);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Title</Form.Label>
        <Form.Control type="text" value={title} onChange={(e) => setTitle(e.target.value)} />
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Start Date</Form.Label>
        <Form.Control type="date" value={dateStart} onChange={(e) => setDateStart(e.target.value)} />
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>End Date</Form.Label>
        <Form.Control type="date" value={dateEnd} onChange={(e) => setDateEnd(e.target.value)} />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Calendar

This component defines 3 state variables: title, dateStart, and dateEnd. When the user enters the values into the fields and clicks "Generate", qrText will be set to the format stated above, with the values used in their specific places.

Just like you did in previous sections, go to src/App.js and add a new tab under <Nav>:

<Nav.Item>
    <Nav.Link eventKey="calendar">Calendar</Nav.Link>
</Nav.Item>

Then, add the component as a tab-pane under Tab.Content:

<Tab.Pane eventKey="calendar">
    <Calendar setQrText={setQrText} />
</Tab.Pane>

And import the Calendar component at the top of the file:

import Calendar from './components/Calendar'

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.

Generate 10 QR Code Types with React

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.

Mail QR Codes

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.

The format of a mail QR code is as follows:

MATMSG:TO:{to};SUB:{subject};BODY:{message};;

Where {to} is the email address this mail should be sent to, {subject} is the subject of the email, and {message} is the message to include in the body.

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.

Create src/components/Mail.js with the following content:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Mail ({ setQrText }) {
  const [to, setTo] = useState('');
  const [subject, setSubject] = useState('');
  const [message, setMessage] = useState('');


  function handleSubmit (e) {
    e.preventDefault();

    setQrText(`MATMSG:TO:${to};SUB:${subject};BODY:${message};;`);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>To Email</Form.Label>
        <Form.Control type="email" value={to} onChange={(e) => setTo(e.target.value)} />
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Subject</Form.Label>
        <Form.Control type="text" value={subject} onChange={(e) => setSubject(e.target.value)} />
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Message</Form.Label>
        <Form.Control as="textarea" value={message} onChange={(e) => setMessage(e.target.value)} />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Mail

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.

Add the new tab in src/App.js in <Nav>:

<Nav.Item>
    <Nav.Link eventKey="mail">Mail</Nav.Link>
</Nav.Item>

Then, add the tab-pane in <Tab.Control>:

<Tab.Pane eventKey="mail">
    <Mail setQrText={setQrText} />
</Tab.Pane>

Finally, import the Mail component at the top of the file:

import Mail from './components/Mail'

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.

Generate 10 QR Code Types with React

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.

Call QR Code

QR Codes can be used to let your users or customers easily call you just by scanning the QR code.

The format for Call QR Code is as follows:

TEL:{phone_number}

Where {phone_number} is the phone number that the person will call when they scan the QR code.

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.

Create the file src/components/Call.js with the following content:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Call ({ setQrText }) {
  const [phoneNumber, setPhoneNumber] = useState('');

  function handleSubmit (e) {
    e.preventDefault();

    setQrText("TEL:" + phoneNumber);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Phone Number</Form.Label>
        <Form.Control type="text" value={phoneNumber} onChange={(e) => setPhoneNumber(e.target.value)} />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Call

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.

Add in src/App.js the tab for "Call":

<Nav.Item>
    <Nav.Link eventKey="call">Call</Nav.Link>
</Nav.Item>

And add a tab-pane for the Call component:

<Tab.Pane eventKey="call">
    <Call setQrText={setQrText} />
</Tab.Pane>

Finally, import Call at the beginning of the file:

import Call from './components/Call'

Open the website. You should see a new "Call" tab. If you click on it, you'll see one field for the phone number.

Generate 10 QR Code Types with React

If you enter a phone number, click "Generate", then scan the QR Code, you'll be able to directly call the phone number.

SMS QR Code

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.

The format for SMS QR Codes is as follows:

smsto:{phoneNumber}:{message}

Where {phoneNumber} is the phone number to send the SMS to, and {message} is the prefilled message. The {message} is optional. So, you can just have the phone number and the user will be able to send you a message without prefilled content.

In this section, you'll create a component that shows the user 2 fields, one for phone number and one for the message content.

Create src/components/Sms.js with the following content:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Sms ({ setQrText }) {
  const [phoneNumber, setPhoneNumber] = useState('');
  const [message, setMessage] = useState('');

  function handleSubmit (e) {
    e.preventDefault();

    setQrText(`smsto:${phoneNumber}:${message}`);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Phone Number</Form.Label>
        <Form.Control type="text" value={phoneNumber} onChange={(e) => setPhoneNumber(e.target.value)} />
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Message (Optional)</Form.Label>
        <Form.Control type="text" value={message} onChange={(e) => setMessage(e.target.value)} />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Sms

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.

Add the tab in src/App.js under <Nav>:

<Nav.Item>
    <Nav.Link eventKey="sms">SMS</Nav.Link>
</Nav.Item>

And add the tab-pane for the Sms component under Tab.Content:

<Tab.Pane eventKey="sms">
    <Sms setQrText={setQrText} />
</Tab.Pane>

Finally, import the component at the top of the file:

import Sms from './components/Sms'

Open the website now and click on the new "SMS" tab. You'll see 2 fields for phone number and message.

Generate 10 QR Code Types with React

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.

Wifi QR Codes

QR Codes can be used to easily connect to a Wifi network. When a person scans the QR code, they can join the network.

The Wifi QR code has the following format:

WIFI:T:{authentication};S:{name};P:{password};H:{hidden};

{authentication} can either be nopass, WPA or WEP. {name} is the name or SSID of the network. {password} is the password of the network and optional. {hidden} is a boolean value (true or false) that indicates whether this network is hidden or not.

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.

Create src/components/Wifi.js with the following content:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Wifi ({ setQrText }) {
  const [authentication, setAuthentication] = useState('nopass');
  const [name, setName] = useState('');
  const [password, setPassword] = useState('');
  const [hidden, setHidden] = useState(false);


  function handleSubmit (e) {
    e.preventDefault();

    setQrText(`WIFI:T:${authentication};S:${name};${authentication !== 'nopass' ? `P:${password};` : ''}H:${hidden};`);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Authentication type</Form.Label>
        <Form.Select value={authentication} aria-label="Authentication" onChange={(e) => setAuthentication(e.target.value)}>
          <option value="nopass">No Password</option>
          <option value="WEP">WEP</option>
          <option value="WPA">WPA</option>
        </Form.Select>
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Network Name (SSID)</Form.Label>
        <Form.Control type="text" value={name} onChange={(e) => setName(e.target.value)} />
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Password (Optional)</Form.Label>
        <Form.Control type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Hidden?</Form.Label>
        <Form.Check 
          type={'checkbox'}
          checked={hidden}
          onChange={(e) => setHidden(e.target.checked)}
        />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Wifi

Add in src/App.js the tab in <Nav>:

<Nav.Item>
    <Nav.Link eventKey="wifi">Wifi</Nav.Link>
</Nav.Item>

And add Wifi as a tab-pane in <Tab.Content>:

<Tab.Pane eventKey="wifi">
    <Wifi setQrText={setQrText} />
</Tab.Pane>

Finally, import Wifi at the beginning of the file:

import Wifi from './components/Wifi'

If you open the website and click on the Wifi tab, you should see 4 fields.

Generate 10 QR Code Types with React

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.

YouTube QR Codes

QR Codes can be used to easily open a YouTube video. They have the following format:

youtube://{videoId}

Where {videoId} is the ID of a video. You can obtain the ID of a video from the v parameter in the URL of the video:

https://www.youtube.com/watch?v={videoId}

You'll create in this section a component that shows a field for the video's ID then generate the QR code for it.

Create js/components/Youtube.js with the following content:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Youtube ({ setQrText }) {
  const [videoId, setVideoId] = useState('');

  function handleSubmit (e) {
    e.preventDefault();

    setQrText('youtube://' + videoId);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Video ID</Form.Label>
        <Form.Control type="text" value={videoId} onChange={(e) => setVideoId(e.target.value)} />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Youtube

Add the new tab in src/App.js inside <Nav>:

<Nav.Item>
    <Nav.Link eventKey="youtube">Youtube</Nav.Link>
</Nav.Item>

And add the tab-pane for YouTube:

<Tab.Pane eventKey="youtube">
    <Youtube setQrText={setQrText} />
</Tab.Pane>

Finally, import the Youtube component at the top of the file:

import Youtube from './components/Youtube'

Open the website and click on the Youtube tab. You'll see one field to enter the video ID.

Generate 10 QR Code Types with React

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.

Instagram QR Codes

QR Codes can be used to lead people to your Instagram account. The format is just like a URL to your profile:

https://instagram.com/{username}

Where {username} is the username of the profile to open in the Instagram app.

Create src/components/Instagram.js with the following content:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Instagram ({ setQrText }) {
  const [username, setUsername] = useState('');

  function handleSubmit (e) {
    e.preventDefault();

    setQrText('https://instagram.com/' + username);

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Username</Form.Label>
        <Form.Control type="text" value={username} onChange={(e) => setUsername(e.target.value)} />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Instagram

In src/App.js add the new tab under <Nav>:

<Nav.Item>
    <Nav.Link eventKey="instagram">Instagram</Nav.Link>
</Nav.Item>

And add the new tab-pane for Instagram under <Tab.Content>:

<Tab.Pane eventKey="instagram">
    <Instagram setQrText={setQrText} />
</Tab.Pane>

Finally, import Instagram at the top of the file:

import Instagram from './components/Instagram'

Open the website and click on the Instagram tab. You'll see a field to enter your username.

Generate 10 QR Code Types with React

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.

Twitter QR Codes

QR Codes can be used to lead people to your Twitter profile or to Tweet something.

The format to lead to a Twitter profile is as follows:

https://twitter.com/{username}

This is similar to Instagram. When the QR Code for this text is scanned, the profile for {username} will be opened in the Twitter app.

The format to allow people to Tweet something with prefilled content is as follows:

https://twitter.com/intent/tweet?text={content}

Where {content} is the content of the tweet.

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.

Create src/components/Twitter.js with the following text:

import { useState } from "react";
import { Button, Form } from "react-bootstrap";

function Twitter ({ setQrText }) {
  const [type, setType] = useState('profile')
  const [text, setText] = useState('');

  function handleSubmit (e) {
    e.preventDefault();

    setQrText('https://twitter.com/' + (type === 'profile' ? text : 'intent/tweet?text=' + text));

    return false;
  }

  return (
    <Form onSubmit={handleSubmit}>
      <Form.Group className="mb-3">
        <Form.Label>Type</Form.Label>
        <Form.Select value={type} aria-label="Type" onChange={(e) => setType(e.target.value)}>
          <option value="profile">Profile</option>
          <option value="tweet">Tweet</option>
        </Form.Select>
      </Form.Group>
      <Form.Group className="mb-3">
        <Form.Label>Username or Tweet Text</Form.Label>
        <Form.Control type="text" value={text} onChange={(e) => setText(e.target.value)} />
      </Form.Group>
      <Button variant="primary" type="submit">
        Generate
      </Button>
    </Form>
  )
}

export default Twitter

In src/App.js add the new tab in <Nav>:

<Nav.Item>
    <Nav.Link eventKey="twitter">Twitter</Nav.Link>
</Nav.Item>

And add the Twitter component in <Tab.Content>:

<Tab.Pane eventKey="twitter">
    <Twitter setQrText={setQrText} />
</Tab.Pane>

Finally, import the Twitter component at the top of the file:

import Twitter from './components/Twitter'

Open the website now and click on the Twitter tab. You'll see 2 fields.

Generate 10 QR Code Types with React

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.

Conclusion

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.

]]>
<![CDATA[What is Mathematical Induction]]>https://blog.shahednasser.com/what-is-mathematical-induction/Ghost__Post__61cb166d61dbd80628bf9865Sun, 26 Dec 2021 13:54:00 GMT

Mathematical induction is one of the most important proof techniques in math.
This technique is like a chain of objects in the picture attached.

Actually, we use this technique in order to prove that a statement p(n) is true for any natural number n.

This technique is divided into two parts:

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).

In the second part, we assume that p(n) is true and then we prove that p(n+1) is also true.

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.

This way of thinking is actually brilliant, and it is one of the issues that mix logic with math.

]]>
<![CDATA[Get started with Medusa Part 3: Exploring our Admin Dashboard]]>https://dev.to/medusajs/get-started-with-medusa-part-3-exploring-our-admin-dashboard-1nknGhost__Post__61c1aa5561dbd80628bf9687Tue, 21 Dec 2021 10:28:37 GMT

In the previous parts of the series, I went over how to set up Medusa, 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.

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.

The code for this tutorial can be found on this GitHub repository. You can also use this GitHub repository 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 Discord.

Dashboard Key Features

Settings

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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)

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.

Order Management

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.

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

You can also either select an existing customer for the order or create a new one.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.
**

Exchanges, Swaps, and Claim Handling

30% of e-commerce orders are returned. 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.

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.

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

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 the order return experience was easy and simple.

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.

Other Features

In addition to some of these key features, Medusa offers the basic features you expect from every e-commerce platform.

Product Management

On the admin dashboard, you can manage your products including variants, stock and inventory, and more.

Get started with Medusa Part 3: Exploring our Admin Dashboard

Customer Management

You can likewise manage your customers from the admin dashboard. You can see their order details, shipping address, and more.

Discount Management

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.

Gift Cards

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 paid commerce version, Medusa lets you add gift cards and manage details like image, values, description, and more.

Easily Add Integrations

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 Contentful or Strapi to add more CMS related fields and features.

You can also add integrations that help you manage your platform’s marketing and analytics. You can integrate email services like Sendgrid or Mailchimp.

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.

Round Up

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.

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.

Customize the Admin Dashboard

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.

Add Admin Endpoint
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.

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).

In the backend in the file src/api/index.js add the following imports at the top of the file:

    import bodyParser from "body-parser"
    import cors from "cors"
    import { projectConfig } from "../../medusa-config"

Then, below the endpoint added in the previous tutorial, add the following:

    const corsOptions = {
      origin: projectConfig. admin_cors.split(","),
      credentials: true,
    }
    router.options('/admin/top-products', cors(corsOptions))
    router.get("/admin/top-products", cors(corsOptions), bodyParser.json(), async (req, res) => {
      const topProductsService = req.scope.resolve("topProductsService")
      res.json({
        products: await topProductsService.getTopProducts()
      })
    })

This will make use of the cors middleware, passing it the admin CORS configuration from medusa-config.js in the root of the backend. Then, you add an OPTIONS and GET endpoints. In the GET endpoint, you retrieve the top products just like you did last time.

Add New Admin Page
Next, you’ll add the new admin page to show the top products. You’ll add the page as a sub-page of the Products section of the admin panel. So, you need to add the page and add it in the sidebar under Products.

Pages in the admin dashboard are added under the directory src/domain. 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.

Let’s take a look at the products directory, for instance. You’ll find inside it an index.js file, which includes the page that you first see when you click on Products in the sidebar. You’ll also find a router inside the file like the following:

    const Products = () => {
      return (
        <Router>
          <ProductIndex path="/" />
          <Details path=":id" />
          <New path="new" />
        </Router>
      )
    }

This adds nested routes under the /products route.

You’ll find under the products directory other directories with nested files for each page.

So, to add a new page you need to create the file top-selling.js under the products directory, then add it as a nested route in index.js.

Create the file src/domain/products/top-selling.js with the following content:

    import React, { useState } from "react"
    import { Link } from "gatsby"
    import _ from "lodash"
    import { Flex, Text, Box, Image } from "rebass"
    import ImagePlaceholder from "../../assets/svg/image-placeholder.svg"
    import Spinner from "../../components/spinner"
    import {
      Table,
      TableHead,
      TableHeaderCell,
      TableHeaderRow,
      TableBody,
      TableRow,
      TableDataCell,
      DefaultCellContent,
    } from "../../components/table"
    import useMedusa from "../../hooks/use-medusa"
    import styled from "@emotion/styled"
    const LinkWrapper = styled(Link)`
      width: 100%;
      height: 100%;
      text-decoration: none;
      color: black;
      > div {
        color: blue;
      }
      &:focus {
        outline: none;
      }
      display: flex;
    `
    const TopSelling = () => {
      const {
        products,
        hasCache,
        isLoading,
        isReloading,
      } = useMedusa("topSelling")
      return (
        <Flex flexDirection="column" pb={5} pt={5}>
          <Flex>
            <Text mb={3} fontSize={20} fontWeight="bold">
              Top Selling Products
            </Text>
          </Flex>
          {(isLoading && !hasCache) || isReloading ? (
            <Flex
              flexDirection="column"
              alignItems="center"
              height="100vh"
              mt="20%"
            >
              <Box height="50px" width="50px">
                <Spinner dark />
              </Box>
            </Flex>
          ) : (
            <Table>
              <TableHead>
                <TableHeaderRow>
                  <TableHeaderCell sx={{ maxWidth: "75px" }} />
                  <TableHeaderCell>Name</TableHeaderCell>
                  <TableHeaderCell>Number of Sales</TableHeaderCell>
                </TableHeaderRow>
              </TableHead>
              <TableBody>
                {products.map(p => {
                  return (
                    <TableRow key={p.id}>
                      <LinkWrapper
                        to={`/a/products${p.is_giftcard ? "/gift-card" : ""}/${
                          p.id
                        }`}
                      >
                        <TableDataCell
                          maxWidth="75px"
                          p={2}
                          height="100%"
                          textAlign="center"
                        >
                          <DefaultCellContent>
                            <Image
                              src={p.thumbnail || ImagePlaceholder}
                              height={38}
                              width={38}
                              p={!p.thumbnail && "8px"}
                              sx={{
                                objectFit: "contain",
                                border: "1px solid #f1f3f5",
                              }}
                            />
                          </DefaultCellContent>
                        </TableDataCell>
                        <TableDataCell>
                          <DefaultCellContent>{p.title}</DefaultCellContent>
                        </TableDataCell>
                        <TableDataCell>
                          <DefaultCellContent>
                            {p.metadata.sales}
                          </DefaultCellContent>
                        </TableDataCell>
                      </LinkWrapper>
                    </TableRow>
                  )
                })}
              </TableBody>
            </Table>
          )}
        </Flex>
      )
    }
    export default TopSelling

This creates the component TopSelling which uses the useMedusa hook to get the top selling products, then show them in a table with the image, name, and number of sales of the product.

The useMedusa hook, which resides in src/hooks/use-medusa.js takes as a first parameter an endpoint name. You can use any of Medusa’s default endpoints like products or orders. useMedusa will check if the endpoint exists in src/services/api.js, then, executes the request to retrieve the data.

So, in order to make sure useMedusa("topSelling") retrieves the top selling products from the custom endpoint you created earlier, you need to add to the exported object in src/services/api.js the following property at the end of it:

    topSelling: {
        list(search = {}) {
          const params = Object.keys(search)
            .map(k => `${k}=${search[k]}`)
            .join("&")
          let path = `/admin/top-products${params && `?${params}`}`
          return medusaRequest("GET", path)
        },
      }

This will send a GET request to /admin/top-products with any parameters that might be passed to the function.

The TopSelling component is ready. You can now add it to the nested router in src/domain/products/index.js:

    const Products = () => {
      return (
        <Router>
          <ProductIndex path="/" />
          <Details path=":id" />
          <New path="new" />
          <TopSelling path="top-selling" />
        </Router>
      )
    }

The last thing left to do is add the link in the sidebar below the Products link. In src/components/sidebar/index.js Find the link to Products and add the link below it next to the Collections link:

    <StyledItemContainer
      to="/a/products/top-selling"
      activeClassName="active"
      partiallyActive
    >
      <Flex alignItems="center" pl={3} width="100%">
        <Text ml="14px" variant="nav" fontSize="12px">
          Top Selling
        </Text>
      </Flex>
    </StyledItemContainer>

Everything is ready. Let’s try it out.

Start the backend server if it’s not started yet with the following command:

    npm start

Then, start the server for the admin dashboard with the following command:

    npm start

Go to the Admin panel link, which by default is localhost:7000 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 admin@medusa-test.comwith the password supersecret.

Once you login, click on Products, and once the sidebar item expands you should see a new menu item Top Selling. 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.

Get started with Medusa Part 3: Exploring our Admin Dashboard

Conclusion and teaser

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.

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 top-productsendpoint to show the user the store’s top products.

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 here. You can see the new design below. You can also sign-up for the release of the new Admin Dashboard here. Disclaimer: The re-design will not change any of the functionality or steps from the walkthrough above.

Get started with Medusa Part 3: Exploring our Admin Dashboard
]]>
<![CDATA[Create Laravel Blog with Strapi v4]]>https://blog.shahednasser.com/create-laravel-blog-with-strapi-v4/Ghost__Post__61ba1908c393bb64592d848eMon, 20 Dec 2021 08:50:50 GMT

Laravel 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.

Strapi 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.

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 this GitHub repository.

Prerequisites

Before you start, you need the following tools on your machine:

  1. Node.js. Only versions 12 and 14 are supported by Strapi, and 14 is recommended.
  2. PHP >= v7.3
  3. Composer

Please note that this tutorial will be using Strapi v4 and Laravel v8.9

Setup Strapi

Start by setting up Strapi. In your terminal, run the following command:

npx create-strapi-app@latest strapi --quickstart

Once the command is done, the server will start at localhost:1337 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.

Once you're done, you'll be redirected to the main dashboard.

Create Laravel Blog with Strapi v4

Create Content-Types

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.

Start by clicking on Create your first Content type in the dashboard. This will open a new page to create content types. Under the Content Types Builder sidebar, click on Create new collection type under  Collection type. This will open a pop-up where you can enter basic and advanced settings.

You'll first create the tags content type. Enter in the Display Name field in the popup Tag. This will automatically generate the singular and plural forms of the content type.

Create Laravel Blog with Strapi v4

Once you're done, click Continue. You can now choose the fields in this content type. tags will only have a name field other than their id. So, click on the Text field type. Then, enter in the Name field name.

Create Laravel Blog with Strapi v4

In the Advanced Settings tab, check the Required checkbox to ensure that all tags have a name.

Since that's the only field you'll add for the Tag content type, click on Finish. Then, when the pop-up closes, click on the Save button at the top right. This will restart the server. Every time you create a content type, the server is restarted.

Next, you'll create the Post content type. Again, click on Create new collection type. In the pop up that opens, enter for Display Name Post, then click on Continue.

For posts, there will be fields for title, content, image, date posted, and tags that the post falls under.

For the title field, choose the Text field and make it required as we did earlier. Once done, click on Add another field.

For the content field, choose the Rich text field, and make it required.

For the image 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.

For the date_posted field, choose the Date field, and choose for Type "datetime". Mark this field required as well.

Finally, for the tags field, choose the Relation field, then for the relation type choose "Post belongs to many Tags".

Create Laravel Blog with Strapi v4

Once you're done, click on Finish, then click on Save at the top right. This will save the new content type and restart the server.

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 Comment.

The Comment content type will have 3 fields. The first is an Email field with the name field. Make sure to set it as required.

The second field is a Rich text field with the name content. This is where the user's comment will go.

The third field is a Relation field between Comment and Post. The relation should be "Post has many Comments".

Create Laravel Blog with Strapi v4

Note that when you create this field a new field will be added automatically in Post called comments.

Once you're done, click on Finish, then click on Save at the top right. This will save the new content type and restart the server.

Our content types are ready!

Add Content

The next step would be to add content. Click on Content Manager in the sidebar.  Start by adding a few tags by clicking on Tag in the Content Manager sidebar, then click on Add new entry at the top right.

When you create content, make sure you click Publish after saving the content.

Next, add posts the same way. You can use Lorem Ipsum Generator if you want to create mock content.

Change Permissions

The last step left is to make posts and tags public so that you can consume them in Laravel.

First, you'll create an API token to use for your requests. In the sidebar, click Settings, then API Token. Click on Add Entry at the top right.

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.

In the Token type field, choose Full Access.

Create Laravel Blog with Strapi v4

Once you're done, click on Save 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.

Next, you'll modify the permissions for authenticated users to be able to query content types and add new entries.

On the sidebar, click Settings, then Roles in the Settings sidebar.

You'll see two roles: Authenticated and Public. Click on the pencil icon on the Authenticated row.

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 Save.

Create Laravel Blog with Strapi v4

Setup Laravel

Now that Strapi is ready, you'll get started with Laravel.

Run the following command to create a new Laravel project:

composer create-project laravel/laravel blog

Once this command is done, change to the directory created:

cd blog

You can then start the server with the following command:

php artisan serve

This will start the server at localhost:8000.

Add Environment Variables

Before you can make requests to Strapi, you need to add 2 environment variables. Add the following environment variables to .env:

STRAPI_URL=http://localhost:1337
STRAPI_API_TOKEN=

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 = sign.

Add Home Page

On the home page, you'll query all posts in Strapi and display them.

Run the following command in your terminal to create a new controller:

php artisan make:controller BlogController

Then, open app/Http/Controllers/BlogController.php and the following method in the class:

public function home () {
    //retrieve the posts from Strapi
    $response = Http::withToken(env('STRAPI_API_TOKEN'))->get(env('STRAPI_URL') . '/api/posts?populate=image,tags');
    $posts = [];

    if ($response->failed()) {
        if (isset($data['error'])) {
        	Log::error('Server error: ' . $data['error']['message']);
        } else {
        	Log::error('Request Failed');
        }
    } else {
        //get posts from response
        $posts = $response->json('data');
    }

    return view('home', ['posts' => $posts]);
}

First, you query Strapi using Laravel's HTTP Client. You use withToken to pass it the API token from .env using the env helper function. Then, you send a get request to the endpoint  localhost:1337/api/posts?populate=image,tags.

Notice that localhost:1337 also is retrieved from .env. 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 /api/{collection_name}.

When you use Strapi's API, you can pass it a lot of useful parameters that allow you to filter, sort, paginate the data, and more. Here, you use the populate parameter which allows you to retrieve a content type with its relations. You use it to retrieve the post with its image and tags.

After sending the request, you can check if the request failed using $response->failed(). If the request failed, you log the error. If not, you set $posts to the data parameter in the response body. Note that you can use the json method to retrieve the parameters from a JSON response, optionally passing it a parameter name as the first element.

Next, you need to add the home view. Create the file resources/views/home.blade.php with the following content:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Blog</title>

        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    </head>
    <body class="antialiased bg-light">
        <div class="container mt-4 py-3 mx-auto bg-white rounded shadow-sm">
            <div class="row">
                @forelse ($posts as $post)
                    <div class="col-2 col-md-4">
                        <div class="card">
                            <img src="{{ env('STRAPI_URL') . $post['attributes']['image']['data']['attributes']['formats']['medium']['url'] }}" 
                                class="card-img-top" alt="{{ $post['attributes']['image']['data']['attributes']['alternativeText'] }}">
                            <div class="card-body">
                                <h5 class="card-title">{{ $post['attributes']['title'] }}</h5>
                                <p class="card-text">{{ substr($post['attributes']['content'], 0, 50) }}...</p>
                                <a href="/post/{{ $post['id'] }}" class="btn btn-primary">Read More</a>
                            </div>
                            <div class="card-footer">
                                @if(count($post['attributes']['tags']['data']))
                                    @foreach ($post['attributes']['tags']['data'] as $tag)
                                        <span class="badge bg-success">{{ $tag['attributes']['name'] }}</span>
                                    @endforeach
                                @endif
                            </div>
                        </div>
                    </div>
                @empty
                    <div class="col">
                        <div class="card">
                            <div class="card-body">
                                This is some text within a card body.
                            </div>
                        </div>
                    </div>
                @endforelse
            </div>
        </div>
    </body>
</html>

This just displays the posts as cards using Bootstrap. Notice that the content type entries that Strapi return has the following format:

{
	"data": {
    	"id",
        "attributes": {
        	"title",
            ...
       	}
    }
}

So, you'll find the content type's fields inside the attributes key of data.

Finally, change the current route in routes/web.php to the following:

Route::get('/', [\App\Http\Controllers\BlogController::class, 'home']);

Let's test it out. Make sure that both Laravel and Strapi's servers are running. Then, open localhost:8000. You'll see the posts you added as cards.

Create Laravel Blog with Strapi v4

Add View Post Page

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.

In app/Http/Controllers/BlogController.php add a new method:

public function viewPost ($id) {
        //retrieve the post from Strapi
        $response = Http::withToken(env('STRAPI_API_TOKEN'))->get(env('STRAPI_URL') . '/api/posts/' . $id . '?populate=image,tags,comments');

        if ($response->failed()) {
            if (isset($data['error'])) {
                Log::error('Server error: ' . $data['error']['message']);
            } else {
                Log::error('Request Failed');
            }

            return response()->redirectTo('/');
        }

        //get post from response
        $post = $response->json('data');

        return view('post', ['post' => $post]);
 }

In this method, you use the $id parameter, which is the post ID, to send a request to Strapi's single entry endpoint. The endpoint's pattern is /api/{collection_name}/{id}. Similar to the previous endpoint, you can also pass it parameters like populate.

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 post.

Now, create resources/views/post.blade.php with the following content:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>{{ $post['attributes']['title'] }} - Blog</title>

        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    </head>
    <body class="antialiased bg-light">
        <div class="container mt-4 py-3 px-5 mx-auto bg-white rounded shadow-sm">
            <h1>{{ $post['attributes']['title'] }}</h1>
            <small class="text-muted d-block">{{ $post['attributes']['date_posted'] }}</small>
            <img src="{{ env('STRAPI_URL') . $post['attributes']['image']['data']['attributes']['formats']['medium']['url'] }}" 
                                class="img-fluid mx-auto d-block my-3" alt="{{ $post['attributes']['image']['data']['attributes']['alternativeText'] }}">
            @if(count($post['attributes']['tags']['data']))
              <div class="mb-3">
                @foreach ($post['attributes']['tags']['data'] as $tag)
                  <span class="badge bg-success">{{ $tag['attributes']['name'] }}</span>
                @endforeach
              </div>
            @endif
            <p class="content">
              {{ $post['attributes']['content'] }}
            </p>

            <hr />
            <form action="/post/{{ $post['id'] }}" method="POST">
              @csrf
              <h2>Add Your Comment</h2>
              <div class="mb-3">
                <label for="email" class="form-label">Email address</label>
                <input type="email" class="form-control" id="email" name="email" required>
              </div>
              <div class="mb-3">
                <label for="content" class="form-label">Your Comment</label>
                <textarea rows="5" class="form-control" id="content" name="content" required></textarea>
              </div>
              <button type="submit" class="btn btn-primary">Submit</button>
            </form>
        </div>
    </body>
</html>

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 attributes field.

This page also has a comments form at the end of it. You'll implement its functionality after this.

Finally, add the new route in routes/web.php:

Route::get('/post/{id}', [\App\Http\Controllers\BlogController::class, 'viewPost']);

Now, open the home page again and click on Read More for one of the posts. A new page will open with the post's content.

Create Laravel Blog with Strapi v4

If you scroll down, you'll see a form to add your comment.

Create Laravel Blog with Strapi v4

Add Comment Functionality

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 POST route to add the comment.

Add the following method in app/Http/Controllers/BlogController.php:

public function addComment (Request $request, $id) {
        $data = [
            "data" => [
                'email' => $request->get('email'),
                'content' => $request->get('content'),
                'post' => $id
            ]
        ];

        $response = Http::withToken(env('STRAPI_API_TOKEN'))->post(env('STRAPI_URL') . '/api/comments', $data);

        if ($response->failed()) {
            if (isset($data['error'])) {
                Log::error('Server error: ' . $data['error']['message']);
            } else {
                Log::error('Request Failed');
            }

            return response()->redirectTo('/');
        }

        //successfully added
        return response()->redirectTo('/post/' . $id);
    }

You first format the data as Strapi likes it. When adding a content type entry, you should nest the data inside a data parameter. Here, you add the email, content, and post fields. Notice that we are skipping validation here for tutorial simplicity.

Then, you send a POST request to the endpoint /api/comments. Strapi's endpoint pattern for adding a content type entry is /api/{collection_name}. You pass the data as a second parameter to the post method.

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.

Next, add before the comment form in resources/views/post.blade.php the following:

<hr/>
@if (count($post['attributes']['comments']['data']))
    <div class="comments">
        <h2>Comments</h2>
        @foreach ($post['attributes']['comments']['data'] as $comment)
            <div class="card mb-3">
                <div class="card-body">
                	{{ $comment['attributes']['content'] }}
                </div>
                <div class="card-footer">
                	By {{ $comment['attributes']['email'] }}
                </div>
            </div>
        @endforeach
    </div>
@endif

This will show the comments if a post has any.

Finally, add the new route in routes/web.php:

Route::post('/post/{id}', [\App\Http\Controllers\BlogController::class, 'addComment']);

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.

Create Laravel Blog with Strapi v4

Conclusion

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.

]]>
<![CDATA[10 Reasons Why You Should Use React for Building Interactive User Interfaces]]>https://blog.shahednasser.com/10-reasons-why-you-should-use-react-for-building-interactive-user-interfaces/Ghost__Post__61bc7669c393bb64592d8688Fri, 17 Dec 2021 12:04:36 GMT

Creating interactive end-user Interfaces is difficult regardless of the programming platform. Web Page design takes time, effort, and attention to detail, but React simplifies the user interface design and developers’ lives.

You may be curious about using React to build User Interfaces (UI). With its excellent JavaScript structure, the growth process is considerably more manageable.

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.

You should hire the best React development company to get your hands on highly efficient and competitive React designers.

What is React

10 Reasons Why You Should Use React for Building Interactive User Interfaces

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.

React is a widely sought-after option for developing user-friendly and engaging web pages and apps that allow developers to be more creative.

What makes React so popular among businesses and brands?

React Interactive UI Features

Simple to use

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.

Declarative

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.

Reusable Elements

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.

Libraries for JavaScript programming

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.

Assistance with Components

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.

SEO-friendly

Facebook put a lot of work on React. Likely the best way to construct great, SEO-friendly user experiences spanning browsers and engines.

Lightweight DOM integration

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.

Expert Data Binding

React lags one-way data binding. It means anybody can trace all modifications made to any data section. Its simplicity is reflected here.

Other Benefits of React

  • Facilitates coding of JavaScript
  • Outstanding cross-platform support
  • Manages dependencies
  • Easy template design
  • UI-driven designs
  • Simple to adopt

Ten Reasons to Use React in Your Project

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.

1. It is simple to learn.

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.

2. Creating rich user interfaces

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.

3. It supports custom components

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.

4. It boosts developers' output

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.

5. It provides quick rendering

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.

6. It's search engine optimized.

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.

7. It includes a growth toolbox

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.

8. Supportive community

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.

9. It improves code stability

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.

10. Numerous Fortune 500 companies use it.

Still undecided about React?

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.

Conclusion

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.

]]>
<![CDATA[React Native Navigation Tutorial]]>https://blog.shahednasser.com/react-native-navigation-tutorial/Ghost__Post__61b1cb7ad752820612f17badThu, 09 Dec 2021 13:38:31 GMT

React Native is one of the most popular cross-platform app development frameworks. Using JavaScript, you can develop native apps for both Android and iOS.

One important part of creating apps is being able to navigate between screens. In this tutorial, you'll learn how to use React Navigation 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.

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 React Native Tutorial: Create Your First App.

You can find the code for this tutorial on this GitHub repository.

Prerequisites

Make sure you have both Node.js and NPM installed on your machine. You can check if they're installed with the following command:

node -v
npm -v

If they're not installed, you can install Node.js and NPM will be installed automatically with it.

After that, make sure you install Expo's CLI if you don't have it installed:

npm install -g expo-cli

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.

You should also install Expo Go on your device to be able to test the app as we go through the tutorial.

Project Setup

Start by creating a new React Native project using Expo's CLI:

expo init react-navigation-tutorial —npm

You'll be then prompted to choose the type of app, choose "blank".

After that the init command will install the dependencies you need for your React Native project.

Once it's done, change to the directory of the project:

cd react-navigation-tutorial

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:

expo install react-native-screens react-native-safe-area-context

Second, install the native stack navigator library:

npm install @react-navigation/native-stack

Now, you have all the libraries required to start using React Navigation.

Finally, install React Native Paper to have beautifully-styled components in your app:

npm install react-native-paper

Set Up React Navigation

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.

In App.js, change the content to the following:

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Provider as PaperProvider } from 'react-native-paper';
import HomeScreen from './screens/HomeScreen';

const Stack = createNativeStackNavigator()

export default function App() {
  return (
    <PaperProvider>
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen name="Home" component={HomeScreen} />
        </Stack.Navigator>
    </NavigationContainer>
    </PaperProvider>
  );
}

Notice that in the returned value of App, you first have <PaperProvider> at the top of the elements. This is just used to make sure all screens share the same theme.

Next, you have the <NavigationContainer>. This component manages the navigation tree and contains the navigation state. So, it should wrap Stack navigators.

Inside <NavigationContainer> you have <Stack.Navigator>. Stack is created using createNativeStackNavigator. This function returns an object containing 2 properties: Screen and Navigator. The Navigator property is a React element and it should be used to wrap the Screen elements to manage routing configurations.

So, inside <Stack.Navigator> you'll have one or more <Stack.Screen> components. For each route, you'll have a <Stack.Screen> component. Now, you just have one component that points to the Home route.

Notice that a Screen component takes the name prop, which is the name of the route and will be referenced later on when navigating to this route, and the component property which is the component to render for this route.

As you can see, you're passing HomeScreen component to the Home route, so you need to create it now.

Create the directory screens, and inside that directory create a new file HomeScreen.js with the following content:

import React from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import { Button, Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function HomeScreen () {
  return (
    <ScrollView style={styles.scrollView}>
      <Card style={styles.card}>
        <Card.Title title="Home Screen" />
      </Card>
    </ScrollView>
  )
}

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: DefaultTheme.colors.background,
    paddingTop: 10
  },
  card: {
    width: '90%',
    marginLeft: 'auto',
    marginRight: 'auto'
  }
});

export default HomeScreen

This will create a basic home screen with a ScrollView component containing a Card component with the title "Home Screen".

You just created your first route with React Navigation! Let's test it out.

In your terminal run to start your app:

npm start

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.

Once the app run, you'll see the Home screen that you created as it's the default and only route.

React Native Navigation Tutorial

In this section, you'll learn how to navigate from one screen to another.

Screens that are inside the Stack Navigation, like HomeScreen in this app, receive a navigation prop. This prop allows us to navigate to other screens in the app.

Let's first create the screen you'll navigate to. Create the file screens/BookScreen.js with the following content:

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function BookScreen () {
  return (
    <View style={styles.container}>
      <Card style={styles.card}>
        <Card.Title title="This is Books Screen" />
      </Card>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: DefaultTheme.colors.background,
    alignItems: 'center',
    paddingTop: 10
  },
  card: {
    width: '90%'
  }
});

export default BookScreen;

This screen is similar to HomeScreen. It just shows a card with the title "This is Books Screen".

Next, add the new route in App.js for BookScreen below the "Home" route:

<Stack.Screen name="Book" component={BookScreen} />

Don't forget to import BookScreen below the imports at the beginning of App.js:

import BookScreen from './screens/BookScreen';

Now, you can navigate to the "Book" route inside this stack navigation. To see how it works, you'll add a button in HomeScreen that when the user clicks will navigate to BookScreen.

In HomeScreen, add the navigation prop to the function:

function HomeScreen ({ navigation })

Then, change the returned value of the function to the following:

return (
    <ScrollView style={styles.scrollView}>
      <Card style={styles.card}>
        <Card.Title title="Navigate to 'Book' Screen" />
        <Card.Content>
          <Button mode="contained" onPress={() => navigation.navigate('Book')}>
            Navigate
          </Button>
        </Card.Content>
      </Card>
    </ScrollView>
  )

You change the title of the card to "Navigate to 'Book' Screen". Then, inside the content of the card, you add a Button component with onPress listener. This listener will be executed when the user presses on the button.

Inside the listener, you use the navigation prop to navigate to the Book screen using the method navigate. The method navigate takes the name of the route to navigate to.

Let's test it out. Run the app again if it isn't running. You should see a new button on the Home screen.

React Native Navigation Tutorial

Try clicking on the Navigate button. You'll be navigated to the BookScreen.

React Native Navigation Tutorial

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.

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 NameScreen which will show a greeting to the user with the name they entered.

Start by adding a new state variable to hold the value of the input you'll add soon in HomeScreen.js:

const [name, setName] = useState('');

Make sure to add an import for useState at the beginning of the file:

import React, { useState } from 'react';

Then, add a new Card component below the existing one:

<Card style={styles.card}>
    <Card.Title title="Navigate with Parameters" />
    <Card.Content>
        <TextInput mode="outlined" label="Name" value={name} onChangeText={(text) => setName(text)} style={styles.textInput} />
            <Button mode="contained" disabled={name.length === 0} onPress={() => navigation.navigate('Name', { name })}>
                Navigate
    	</Button>
    </Card.Content>
</Card>

This new card has a TextInput with the value name, and on the onChangeText event, which occurs when the user makes changes to the text inside the input, you change the value of the name state variable.

Below the input, you have a button that is disabled when the name state variable is empty. You also add an onPress event listener which navigates the user to the Name route.

Notice that you're using the same navigation.navigate 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 name variable inside the object.

One last thing you need to do in the HomeScreen is change the styles object to the following:

const styles = StyleSheet.create({
  scrollView: {
    backgroundColor: DefaultTheme.colors.background,
    paddingTop: 10
  },
  card: {
    width: '90%',
    marginLeft: 'auto',
    marginRight: 'auto',
    marginBottom: 10
  },
  textInput: {
    marginBottom: 10
  }
});

This just makes some changes to the card property and adds a new property textInput.

You'll now create the NameScreen which will be the component for the "Name" route you'll add soon. Create screens/NameScreen.js with the following content:

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function NameScreen ({ route }) {
  const { name } = route.params;

  return (
    <View style={styles.container}>
      <Card style={styles.card}>
        <Card.Title title={`Hello, ${name}`} />
      </Card>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: DefaultTheme.colors.background,
    alignItems: 'center',
    paddingTop: 10
  },
  card: {
    width: '90%'
  }
});

export default NameScreen;

This screen is essentially the same as BookScreen, however, notice the route prop passed to the function.

As mentioned before, the components inside the navigation stack receive a navigation prop to navigate between screens. They also receive a route prop which you can use to get the parameters passed to the screen using route.params.

So, in NameScreen, you retrieve the value entered in the Name input in the HomeScreen, which is passed when navigating to the NameScreen when the button is clicked using route.params:

const { name } = route.params;

You then show the user a greeting inside a card using the name parameter.

One last thing left to do is add the "Name" route to the navigation stack. Add a new <Stack.Screen> below the previous ones in App.js:

<Stack.Screen name="Name" component={NameScreen} />

And import NameScreen below other imports at the beginning of the file:

import NameScreen from './screens/NameScreen';

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.

React Native Navigation Tutorial

Try entering your name, then click the "Navigate" button below the input. You'll be navigated to the NameScreen and you'll see your name.

React Native Navigation Tutorial

You can try going back then changing the value of the name. The name in the NameScreen will change accordingly.

Configure the Header

Change the title

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.

In this section, you'll add a new input in HomeScreen that will let you to enter a title, then on clicking the navigate button you'll be navigated to a new screen TitleScreen, whose title will change based on the title entered in the input in HomeScreen.

Start by adding a new state variable in HomeScreen.js to store the title:

const [title, setTitle] = useState('');

Then, add a new card below the previous cards:

<Card style={styles.card}>
        <Card.Title title="Navigate to Route with Title" />
        <Card.Content>
          <TextInput mode="outlined" label="Title" value={title} onChangeText={(text) => setTitle(text)} style={styles.textInput} />
          <Button mode="contained" disabled={title.length === 0} onPress={() => navigation.navigate('Title', { title })}>
            Navigate
          </Button>
        </Card.Content>
      </Card>

This is pretty much the same as the card we added in the previous section. The only difference is that it uses the title state variable, and the listener for onPress for the button navigates to the route "Title", passing the title as a parameter.

Next, create the file screens/Title.js with the following content:

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function TitleScreen () {
  return (
    <View style={styles.container}>
      <Card style={styles.card}>
        <Card.Title title="This is title screen" />
      </Card>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: DefaultTheme.colors.background,
    alignItems: 'center',
    paddingTop: 10
  },
  card: {
    width: '90%'
  }
});

export default TitleScreen;

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.

That's because you can change the title of a screen by passing an options parameter to <Stack.Screen> when adding the route.

In App.js, add an import for TitleScreen below other imports at the beginning of the file:

import TitleScreen from './screens/TitleScreen';

Then, add the new route below previous <Stack.Screen>:

<Stack.Screen name="Title" component={TitleScreen} options={({route}) => ({title: route.params.title})} />

Every Stack.Screen component can take an options prop. The options prop can be an object like so:

options={{title: "Hello"}}

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 route, which is similar to the route parameter you used in NameScreen:

options={({route}) => ({title: route.params.title})}

In this function, you return an object that has a title property with the value route.params.title. 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 options prop.

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:

React Native Navigation Tutorial

Try entering any title you want in the input then click on Navigate. You'll see that you'll be navigated to the TitleScreen, but the title will be the value you entered in the input.

React Native Navigation Tutorial

You can try going back then changing the value entered in the input. The title of the screen will change accordingly.

Add Header Button

Another option you can add is header buttons. You can customize what your header shows on the left and right by using the headerRight and headerLeft properties in the options param of <Stack.Screen>.

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.

In App.js, add to the "Home" route a prop option:

<Stack.Screen name="Home" component={HomeScreen} options={{
            headerRight: () => (
              <IconButton icon="alert-outline" onPress={() => alert('You\'re awesome!')} color={DefaultTheme.colors.notification} />
            )
}} />

In the options prop, you pass an object with the property headerRight. The headerRight property can be a component that you can render elements inside. You render an IconButton component, which is a button that only has an icon without text. In the onPress event listener, you show an alert to the user.

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.

React Native Navigation Tutorial

Click on it and you'll see an alert.

React Native Navigation Tutorial

In React Navigation, you can subscribe to two events: focus and blur. The focus event will occur every time the screen is opened and is currently the main screen. The blur event will occur whenever a screen was in focus but navigation occurs that makes the screen not the current main screen. Simply put, the focus event is when the screen is visible to the user, and the blur event occurs when a screen was visible to a user but isn't anymore.

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 blur event.

To subscribe to events, in a useEffect callback inside a component, you can use navigation.addListener passing it the name of the event as a first parameter, and the event handler as a second parameter. The addListener method returns an unsubscribe function which you should return in the useEffect callback.

In HomeScreen.js, add an import for useEffect at the beginning of the file:

import React, { useEffect, useState } from 'react';

Then, add a new state variable counter inside the HomeScreen component:

const [counter, setCounter] = useState(0);

After that add the useEffect callback that will register the event handle for the blur event:

useEffect(() => {
    return navigation.addListener('blur', () => {
      setCounter(counter + 1);
    });
  });

As you can see, you use navigation.addListener to add an event listener to the blur 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.

Finally, you'll show the counter at the top of the screen. In ScrollView, add a new card before the previously added cards:

<Card style={styles.card}>
	<Card.Title title={`Navigation Count: ${counter}`} />
</Card>

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.

Go Back

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.

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 BackScreen which you can go to from the HomeScreen. 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 HomeScreen.

Create the file screens/BackScreen.js with the following content:

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Button, Card } from 'react-native-paper';
import { DefaultTheme } from 'react-native-paper';

function BackScreen ({ navigation }) {
  return (
    <View style={styles.container}>
      <Card style={styles.card}>
        <Card.Title title="This is Back Screen" />
        <Card.Content>
          <Button mode="contained" onPress={() => navigation.goBack()}>
            Go Back
          </Button>
        </Card.Content>
      </Card>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    backgroundColor: DefaultTheme.colors.background,
    alignItems: 'center',
    paddingTop: 10
  },
  card: {
    width: '90%'
  }
});

export default BackScreen;

This screen is pretty much the same as other screens. The things you should note is that, first, the screen has uses the navigation 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 navigation prop to go back using the goBack method:

<Button mode="contained" onPress={() => navigation.goBack()}>

Now, go to the HomeScreen and add a new card at the end of the ScrollView:

<Card style={styles.card}>
    <Card.Title title="Navigate to 'Back' Screen" />
    <Card.Content>
        <Button mode="contained" onPress={() => navigation.navigate('Back')}>
            Navigate
    	</Button>
    </Card.Content>
</Card>

This card just shows a button to navigate to the route "Back". Let's add that route now.

In App.js add a new <Stack.Screen> component below the previously added ones:

<Stack.Screen name="Back" component={BackScreen} />

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.

React Native Navigation Tutorial

Click on "Navigate" on the last card. You'll be navigated to the BackScreen.

React Native Navigation Tutorial

Click on the "Go Back" button in the card. You'll be taken back to the HomeScreen.

Conclusion

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.

Although this covers most use cases for using React Navigation, be sure to check out their documentation for more details on how to use it.

]]>
<![CDATA[4 Ways to Annoy Your Users and Push Them Away]]>https://blog.shahednasser.com/4-ways-to-annoy-your-users-and-push-them-away/Ghost__Post__61af8e5b34d386060b4f22cdWed, 08 Dec 2021 12:56:53 GMT

Let me start by saying that, no, this article does not encourage you to annoy your users.

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.

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.

Overuse of Pop-ups

4 Ways to Annoy Your Users and Push Them Away

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?

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.

And that was just for one pop-up. Imagine how your users think if you use a pop-up on every chance you get.

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.

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.

Ads Exceeding The Content

4 Ways to Annoy Your Users and Push Them Away

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.

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.

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.

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 Carbon 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.

Shifting Layout

4 Ways to Annoy Your Users and Push Them Away

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?

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.

This is so annoying that it's one of the 3 core web vital metrics. Cumulative Layout Shift (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".

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.

This doesn't just annoy users. The core web vitals metrics are used across Google analytics and insights tools for your website, including Google's Search Console. 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.

If this happens on your website and you're unsure how you can resolve it, take a look at tips to improve your CLS score and try to apply them on your website.

Impossible Unsubscription

4 Ways to Annoy Your Users and Push Them Away

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.

For starters, some websites' newsletters go into a great deal of hiding their unsubscription link. They hide it among the very fine lines at the end of the email's footer, and you basically need a microscope to find it.

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.

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.

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.

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.

Conclusion

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.

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.

]]>
<![CDATA[Programming Languages and Framework to Learn in 2022]]>https://blog.shahednasser.com/programming-languages-and-framework-to-learn-in-2022/Ghost__Post__61acc79934d386060b4f215eMon, 06 Dec 2021 12:09:31 GMT

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.

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.

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.

If you're interested in learning any of these programming languages, be sure to check out these websites that can help you learn and practice different programming languages.

Programming Languages

Python

According to PYPL, Python 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 more types of projects for different platforms.

Python is one of the highly demanded skills among job postings. On Glassdoor, you can find over 14k jobs that require Python. By learning Python, you have a higher chance of finding a job or upgrading your job.

JavaScript

JavaScript keeps rising in popularity over the years, as its possibilities keep expanding. It currently is the #3 popular language according to PYPL, and according to Statista, it's the #1 programming language used by developers worldwide in 2021. 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.

JavaScript is another programming language that's popular in job postings. On Glassdoor, you can find over 11k job postings that require JavaScript.

Java

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 PYPL, 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.

As for job postings, Java is fairly popular as well among job postings. On Glassdoor, you can find over 8k job postings related to Java.

Swift

If you're interested in developing iOS apps, Swift is what you need to learn. Ranking #8 on PYPL, 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.

By learning Swift, you open your doors to becoming an iOS developer. Currently, there are over 2k jobs for iOS developers on Glassdoor.

Frameworks/Libraries

React

React is the most used web development framework worldwide in 2021 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.

React's popularity has been increasing among job postings. At the moment, it has over 5k job postings on Glassdoor.

Flutter

Flutter 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 most used cross-platform mobile framework in 2021.

Flutter uses Dart as a programming language, so you'll need to learn it as well. At the moment, Flutter has over 500 job postings on Glassdoor.

Tailwind CSS

Tailwind CSS 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.

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.

Express

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 almost 3k full-stack developer jobs on Glassdoor.

React Native

React Native 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 the #2 most used cross-platform mobile framework among developers in 2021. At the moment, React Native has over 5k job postings on Glassdoor.

Laravel

Laravel is a PHP 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 over 600 job postings on Glassdoor that require Laravel.

Vue.js

Vue.js is another popular JavaScript framework. According to Statista, it's the fifth most used web framework 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 over 700 job postings on Glassdoor.

Conclusion

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.

]]>
<![CDATA[Implementing RBAC in Laravel Tutorial]]>https://blog.shahednasser.com/implementing-rbac-in-laravel-tutorial/Ghost__Post__618135d1e78fe4060e2bf5baThu, 02 Dec 2021 15:07:47 GMT

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.

In this tutorial, you'll learn how to implement RBAC in Laravel using Bouncer. Bouncer is a PHP package that lets you add roles and abilities to your Eloquent models.

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 this GitHub repository.

Prerequisites

You need to download Composer to follow along in this tutorial.

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.

You can check your PHP version in the terminal:

php -v

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 Node.js.

Project Setup

The first step is to set up the Laravel project. In your terminal, run the following command:

composer create-project laravel/laravel laravel-rbac-tutorial

Once that is done, switch to the directory of the project:

cd laravel-rbac-tutorial

Then, you need to add your database configuration on .env:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

Now migrate Laravel's default migrations to your database:

php artisan migrate

This will add Laravel's default tables as well as the users table.

Implement Authentication

To implement authentication easily, you can use Laravel UI. Install it with this command:

composer require laravel/ui

Then, run the following command to add the UI for authentication:

php artisan ui bootstrap --auth

This will add the directory app/Http/Controllers/Auth with the controllers needed to implement authentication. It will also add the necessary view files  resources/views to add pages like login and register.

Then, compile the CSS and JavaScript assets added by the previous command:

npm install && npm run dev

This command might end in an error. If so, run the dev script again:

npm run dev

Finally, go to app/Providers/RouteServiceProvider.php and change the value for the constant HOME:

public const HOME = '/';

Now, run the server:

php artisan serve

Then, go to localhost:8000. You'll see the login form.

Implementing RBAC in Laravel Tutorial

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.

Implementing RBAC in Laravel Tutorial

After you register as a user, you'll be logged in.

Implementing RBAC in Laravel Tutorial

Add Posts

Now, you'll add posts that the user will be able to create.

Start by creating a migration:

php artisan make:migration create_posts_table

This will create a new migration file in database/migrations with the file name's suffix create_posts_table.

Open the migration file and replace its content with the following:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->longText('content');
            $table->foreignId('user_id')->constrained()->cascadeOnUpdate()->cascadeOnDelete();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

Now, migrate the changes to create the posts table:

php artisan migrate

Next, create the file app/Models/Post.php with the following content:

<?php

/**
 * Created by Reliese Model.
 */

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;

/**
 * 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
 */
class Post extends Model
{
	protected $table = 'posts';

	protected $casts = [
		'user_id' => 'int'
	];

	protected $fillable = [
		'title',
		'content',
		'user_id'
	];

	public function user()
	{
		return $this->belongsTo(User::class);
	}
}

Add Post Form Page

You'll now add the page the user will use to create a new post or edit an old one.

In your terminal, run:

php artisan make:controller PostController

This will create a new controller in app/Http/Controllers/PostController.php. Open it and add a constructor method:

/**
 * Create a new controller instance.
 *
 * @return void
 */
public function __construct()
{
    $this->middleware('auth');
}

This adds the auth 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.

Next, add the postForm function that renders the post form view:

public function postForm ($id = null) {
    /** @var User $user */
    $user = Auth::user();

    $post = null;
    if ($id) {
        /** @var Post $post */
        $post = Post::query()->find($id);
        if (!$post || $post->user->id !== $user->id) {
            return response()->redirectTo('/');
        }
    }

    return view('post-form', ['post' => $post]);
}

Notice that this receives an optional id 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.

Then, create the view resources/views/post-form.blade.php with the following content:

@extends('layouts.app')

@push('head_scripts')
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/trix@1.3.1/dist/trix.css">
@endpush

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ $post ? __('Edit Post') : __('New Post') }}</div>

                <div class="card-body">
                    <form method="POST" action="#">
                        @csrf
                        @error('post')
                            <div class="alert alert-danger">{{ $message }}</div>
                        @enderror
                        <div class="form-group">
                            <label for="title">{{ __('Title') }}</label>
                            <input type="text" name="title" id="title" placeholder="Title" required 
                               value="{{ $post ? $post->title : old('title') }}" class="form-control @error('title') is-invalid @enderror" />
                            @error('title')
                                <span class="invalid-feedback">{{ $message }}</span>
                            @enderror
                        </div>
                        <div class="form-group">
                            <label for="content">{{ __('Content') }}</label>
                            @error('content')
                                <span class="invalid-feedback">{{ $message }}</span>
                            @enderror
                            <input id="content" type="hidden" name="content" value="{{ $post ? $post->content : old('content') }}">
                            <trix-editor input="content"></trix-editor>
                        </div>
                        <div class="form-group">
                            <button type="submit" class="btn btn-primary">{{ __('Submit') }}</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/trix@1.3.1/dist/trix.js"></script>
@endsection

This shows a form with 2 inputs. A title text input, and a text editor for the content. The text editor is Trix, an easy-to-use open-source editor.

You still need to add the link to the page. So, in resources/views/layouts/app.blade.php add the following menu item in the ul under the comment <!-- Left Side Of Navbar -->:

<li class="nav-item">
    <a class="nav-link" href="{{ route('post.form') }}">{{ __('New Post') }}</a>
</li>

Finally, add the route to the page in routes/web.php:

Route::get('/post/{id?}', [PostController::class, 'postForm'])->name('post.form');

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.

Implementing RBAC in Laravel Tutorial

Save Posts

Before you implement the save functionality for posts, it's time to use Bouncer to implement RBAC.

In your terminal, run the following to install Bouncer:

composer require silber/bouncer v1.0.0-rc.10

Then, in app/Models/User.php make the following changes:

use Silber\Bouncer\Database\HasRolesAndAbilities;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, HasRolesAndAbilities;

Next, run the following command to add the migrations that Bouncer needs:

php artisan vendor:publish --tag="bouncer.migrations"

Finally, migrate these changes:

php artisan migrate

Bouncer is now ready to use. You can now add the save post functionality.

In app/Http/Controllers/PostController.php add the new savePost method:

public function savePost (Request $request, $id = null) {
    /** @var $user */
    $user = Auth::user();

    Validator::validate($request->all(), [
    'title' => 'required|min:1',
    'content' => 'required|min:1'
    ]);

    //all valid, validate id if not null
    /** @var Post $post */
    if ($id) {
        $post = Post::query()->find($id);
        if (!$post) {
        return back()->withErrors(['post' => __('Post does not exist')]);
        }
    } else {
    	$post = new Post();
    }

    //set data
    $post->title = $request->get('title');
    $post->content = $request->get('content');
    if (!$post->user) {
    	$post->user()->associate($user);
    }
    $post->save();

    if (!$id) {
    	Bouncer::allow($user)->toManage($post);
    }

    return response()->redirectToRoute('post.form', ['id' => $post->id]);
}

In this method, you first validate that both title and content were entered in the form. Then, if the optional parameter id is passed to the method you validate if it exists and if it belongs to this user. This is similar to the postForm method.

After validating everything, you set title and content. Then, if the post is new you set the current user as the owner of the post with $post->user()->associate($user);.

The important bit is here:

if (!$id) {
	Bouncer::allow($user)->toManage($post);
}

Using the Bouncer facade, you can use functions like allow, which takes a user model. Then, you can give different types of permissions to the user. By using toManage, you give the user all sorts of management permissions over the $post instance.

Now, add the route for this method in routes/web.php:

Route::post('/post/{id?}', [PostController::class, 'savePost'])->name('post.save');

Finally, change the form action in resources/views/post-form.blade.php:

<form method="POST" action="{{ route('post.save', ['id' => $post ? $post->id : null]) }}">

If you go now the New Post page and try adding a post by filling the title and content fields then clicking Submit, you'll be redirected back to the form with the content filled in which means the post has been added.

Show Posts

To make the posts added visible to the user, change the index method in app/Http/Controller/HomeController.php to the following:

/**
* Show the application dashboard.
*
* @return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
    /** @var User $user */
    $user = Auth::user();
    //get all posts
    $posts = Post::query()->where('user_id', $user->id)->get();
    return view('home', ['posts' => $posts]);
}

This will retrieve the posts that are made by the currently logged-in user.

Next, change resources/views/home.blade.php to the following:

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <h1>{{ __('My Posts') }}</h1>
            @forelse ($posts as $post)
                <div class="card">
                    <div class="card-header">{{ $post->title }}</div>

                    <div class="card-body">
                        {!! $post->content !!}
                    </div>

                    <div class="card-footer">
                        {{ __('By ' . $post->user->name) }} - 
                        <a href="{{ route('post.form', ['id' => $post->id]) }}">{{ __('Edit') }}</a>
                    </div>
                </div>
            @empty
                <div class="card">
                    <div class="card-body">
                        {{ __('You have no posts') }}
                    </div>
                </div>
            @endforelse
        </div>
    </div>
</div>
@endsection

This will show the list of posts that the user has added if there are any.

If you open the home page now, you should see the post you added earlier.

Implementing RBAC in Laravel Tutorial

Add View and Edit Access

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.

In resources/views/home.blade.php change the element with class .card-footer that holds the Edit link to the following:

<div class="card-footer">
  {{ __('By ' . $post->user->name) }} - 
  <a href="{{ route('post.form', ['id' => $post->id]) }}">{{ __('Edit') }}</a> - 
  <a href="{{ route('post.access', ['id' => $post->id, 'type' => 'view']) }}">{{ __('Change view access...') }}</a> - 
  <a href="{{ route('post.access', ['id' => $post->id, 'type' => 'edit']) }}">{{ __('Change edit access...') }}</a>
</div>

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.

In app/Http/Controllers/PostController.php add a new method accessForm:

public function accessForm ($id, $type) {
    /** @var App/Models/User $user */
    $user = Auth::user();

    /** @var Post $post */
    $post = Post::query()->find($id);
    if (!$post || $post->user->id !== $user->id) {
        return response()->redirectTo('/');
    }

    //get all users
    $users = User::query()->where('id', '!=', $user->id)->get();

    return view('post-access', ['post' => $post, 'users' => $users, 'type' => $type]);
}

This route receives 2 parameters: id which is the post ID, and type which is the type of access. The type of access can be view or edit.

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 post-access which we'll create now.

Create resources/views/post-access.blade.php with the following content:

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <h1>{{ __("Change " . ucwords($type) . " Access to Post") }}</h1>
            <div class="card">

              <div class="card-body">
                <form method="POST" action={{ route('post.access.save', ['id' => $post->id, 'type' => $type]) }}>
                  @csrf 
                  @forelse ($users as $user)
                    <div class="form-group">
                      <label for="user_{{ $user->id }}">
                        <input type="checkbox" name="users[]" id="user_{{ $user->id }}" value="{{ $user->id }}" 
                        class="form-control d-inline mr-3" @if ($user->can($type, $post)) checked @endif 
                        style="width: fit-content; vertical-align: middle;" />
                         <span>{{ $user->name }}</span>
                      </label>
                    </div>
                  @empty
                    {{ __('There are no users') }}
                  @endforelse
                  <div class="form-group">
                    <button type="submit" class="btn btn-primary">{{ __('Save') }}</button>
                  </div>
                </form>
              </div>
          </div>
        </div>
    </div>
</div>
@endsection

This shows the list of users with checkboxes. Those who already have access will already by checked, others unchecked.

Now, you'll create the route that handles saving the access for the post. In app/Http/Controllers/PostController.php add the new method saveAccess:

public function saveAccess (Request $request, $id, $type) {
    /** @var User $user */
    $user = Auth::user();

    /** @var Post $post */
    $post = Post::query()->find($id);
    if (!$post || $post->user->id !== $user->id) {
        return response()->redirectTo('/');
    }

    $users = $request->get('users', []);
    $disallowedUserNotIn = $users;
    $disallowedUserNotIn[] = $user->id;
    //disallow users not checked
    $disallowedUsers = User::query()->whereNotIn('id', $disallowedUserNotIn)->get();

    /** @var User $disallowedUser */
    foreach ($disallowedUsers as $disallowedUser) {
        $disallowedUser->disallow($type, $post);
    }

    //allow checked users
    $allowedUsers = User::query()->whereIn('id', $users)->get();

    /** @var User $allowedUser */
    foreach($allowedUsers as $allowedUser) {
        $allowedUser->allow($type, $post);
    }

    return back();
}

This route also receives 2 parameters id and type, same as accessForm. You also validate the post by checking that it exists and that it belongs to the current user.

Then, you retrieve the checked users from the request. There are 2 actions to do here: disallow unchecked users to perform the action type on the post, and allow checked users to perform the action type on the post.

So, you first retrieve the users that are not in the array $users which holds the checked user IDs. Then, you loop over them to perform the following method on each of them:

$disallowedUser->disallow($type, $post);

When the trait HasRolesAndAbilities is added to a model, which we did earlier to the model User, a set of methods are added to that m0del. One of them is disallow which disallows the user a certain ability and you can specify a model to be more specific about what that ability is disabled on.

So, here you are disallowing the user in the loop to perform the action $type on the post $post.

Next, you retrieve the users that are in the $users array and that should be granted the ability to perform action $type on them. You loop over them and perform the following method:

$allowedUser->allow($type, $post);

Similar to disallow, allow is another method that is added by the trait HasRolesAndAbilities. It allows the user to have the ability $type either in general or on a given model that is specified as a second parameter.

Here, you allow the user to perform the action $type on the post $post.

Now, add the new routes in routes/web.php:

Route::get('/post/access/{id}/{type}', [PostController::class, 'accessForm'])->name('post.access');

Route::post('/post/access/{id}/{type}', [PostController::class, 'saveAccess'])->name('post.access.save');

Now, there are some changes left to do. First, you need to change the condition in postForm which allows users who have the permission to edit or view the post to access the page:

if (!$post || ($post->user->id !== $user->id && !$user->can('edit', $post) && !$user->can('view', $post))) {
    return response()->redirectTo('/');
}

You also need to allow users who have edit permission to edit the post in savePost:

if (!$post || ($post->user->id !== $user->id && !$user->can('edit', $post))) {
	return back()->withErrors(['post' => __('Post does not exist')]);
}

In app/Http/Controllers/HomeController.php in the index method change the method to also retrieve the posts that the user has edit or view permissions on:

/**
     * Show the application dashboard.
     *
     * @return \Illuminate\Contracts\Support\Renderable
     */
    public function index()
    {
        /** @var User $user */
        $user = Auth::user();
        //get all posts
        $posts = Post::query()->where('user_id', $user->id);
        //get posts that the user is allowed to view or edit
        $postIds = [];
        $abilities = $user->getAbilities();
        /** @var \Silber\Bouncer\Database\Ability */
        foreach ($abilities as $ability) {
            $postIds[] = $ability->entity_id;
        }
        $posts = $posts->orWhereIn('id', $postIds)->get();
        return view('home', ['posts' => $posts]);
    }

This is done using the getAbilities method that is added on the User model like allow and disallow. Each ability holds the id of the model it represents under entity_id. 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.

In resources/views/home.blade.php change the element with class .card-footer to the following:

<div class="card-footer">
    {{ __('By ' . $post->user->name) }} - 
    <a href="{{ route('post.form', ['id' => $post->id]) }}">{{ __('View') }}</a>
    @can('manage', $post)
        - <a href="{{ route('post.access', ['id' => $post->id, 'type' => 'view']) }}">{{ __('Change view access...') }}</a> - 
        <a href="{{ route('post.access', ['id' => $post->id, 'type' => 'edit']) }}">{{ __('Change edit access...') }}</a>
    @endcan
</div>

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 @can blade directive which accepts the ability name and optionally a model instance. In this case, we check if the current user can manage the post $post.

Finally, you need to make changes to resources/views/post-form.blade.php 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.

Change the content of the element with the class card to the following:

<div class="card-header">{{ $post ? __('View Post') : __('New Post') }}</div>

<div class="card-body">
    <form method="POST" action="{{ route('post.save', ['id' => $post ? $post->id : null]) }}">
        @csrf
        @error('post')
        	<div class="alert alert-danger">{{ $message }}</div>
        @enderror
        @if ($post && !Auth::user()->can('edit', $post))
        	<div class="alert alert-info">{{ __('You have view permissions only') }}</div>
        @endif
        <div class="form-group">
            <label for="title">{{ __('Title') }}</label>
            <input type="text" name="title" id="title" placeholder="Title" required 
            value="{{ $post ? $post->title : old('title') }}" class="form-control @error('title') is-invalid @enderror" 
            @if($post && !Auth::user()->can('edit', $post)) disabled="true" @endif />
            @error('title')
            	<span class="invalid-feedback">{{ $message }}</span>
            @enderror
        </div>
        <div class="form-group">
            <label for="content">{{ __('Content') }}</label>
            @error('content')
            	<span class="invalid-feedback">{{ $message }}</span>
            @enderror
            @if($post && !Auth::user()->can('edit', $post))
            	{!! $post->content !!}
            @else 
            	<input id="content" type="hidden" name="content" value="{{ $post ? $post->content : old('content') }}">
            	<trix-editor input="content"></trix-editor>
            @endif
        </div>
        @if(!$post || Auth::user()->can('edit', $post))
        	<div class="form-group">
        		<button type="submit" class="btn btn-primary">{{ __('Submit') }}</button>
        	</div>
        @endif
    </form>
</div>

This makes the title 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 edit permissions.

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.

Implementing RBAC in Laravel Tutorial

Check the checkbox and click save. This will give the new user the ability to view the post.

Now, log out and log in again with the new user. You'll see the post in the home page.

Implementing RBAC in Laravel Tutorial

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.

Implementing RBAC in Laravel Tutorial

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.

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.

Implementing RBAC in Laravel Tutorial

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.

Conclusion

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.

Be sure to check out Bouncer's documentation to learn more about what you can do with the package.

]]>
<![CDATA[Invideo Review: Make creative video with online video editor]]>https://blog.shahednasser.com/invideo-review-make-creative-video-with-online-video-editor/Ghost__Post__61a4e66053259e060be11801Mon, 29 Nov 2021 15:05:15 GMT

In this era of digital technology, 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.

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.

What’s InVideo?

Put simply, InVideo 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.

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:

  • Intro/outro videos
  • Promotional and product videos
  • Greetings and motion quotes
  • Tutorials
  • Video presentations
  • Webinars
  • Social media videos
  • YouTube video testimonials
  • Promos

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.

Use Readymade Templates for Making Creative Videos

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.

Now, when it comes to using InVideo, there are three varied ways of using it to your best advantage.

  • Premade Templates: You can use the premade templates available with this tool for making and editing visual matter without taking a lot of time.
  • Text-to-Video: 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.
  • Blank Template: 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.

Engaging Videos Are Easy to Make with InVideo

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.

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.

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.

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.

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.

Express Your Creativity to the Fullest

With InVideo, you can make professional documentaries and even social media 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.

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.

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.

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.

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.

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.

The Bottom Line

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.

If you are on the lookout for that perfect tool to help you make business videos for product promotion, 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.

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!

]]>
<![CDATA[Internet of Things Application Development: 8 Inspiring Projects]]>https://blog.shahednasser.com/internet-of-things-application-development-8-inspiring-projects/Ghost__Post__619f5eb353259e060be117d7Thu, 25 Nov 2021 10:06:35 GMT

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.

In this article, we’ll look at the most exciting projects to come out of the IoT application development services industry in recent years.

The Most Exciting Internet of Things Application Development Projects (So Far)

Manufacturing Projects

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.

Example 1: 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.

Transportation

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.

Example 2: 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.

Example 3: 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.

Example 4: 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.

Energy

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.

Example 5: 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.

Retail

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.

Example 6: 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.

Example 7: 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.

Smart Cities

We are already familiar with smart homes, but the concept is being expanded on to include larger cities and towns.

Example 8: 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.

Conclusion

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.

]]>
<![CDATA[How to Build a Social Media App]]>https://blog.shahednasser.com/how-to-build-a-social-media-app/Ghost__Post__619f558953259e060be117bbThu, 25 Nov 2021 09:30:23 GMT

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.

Determine What Kind of App You Want to Create

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.

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 knowing your target audience, you can learn more about what people are using and what they would like to see added to their existing platforms.

Decide How Your App Will Work

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.

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.

Choose a Platform

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.

For example, iOs developers 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.

Test Different Features and Prototypes

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.

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.

Market Your App

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.

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.

The Bottom Line

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 social media platform will become the most popular in the world!

]]>
<![CDATA[React Context Tutorial For Beginners]]>https://blog.shahednasser.com/react-context-tutorial-for-beginners/Ghost__Post__617bfd6f7ec5e905d9bde7ddWed, 10 Nov 2021 14:43:44 GMT

Context 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.

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.

You can find the code for this tutorial on this GitHub repository.

Project Setup

In your terminal, use the following command to create a new React app:

npx create-react-app react-context-tutorial

Once the installation is done, go to the react-context-tutorial directory:

cd react-context-tutorial

Then, install the following dependencies which you'll use throughout the tutorial:

npm i axios react-bootstrap bootstrap@5.1.3 react-cookie react-router-dom

Here's what each dependency is for:

  1. axios: to send POST request to log in the user.
  2. bootstrap and react-bootstrap: for easy styling
  3. react-cookie: to store the user token in the cookies
  4. react-router-dom: to add pages and routing between them.

Create the Context

You need to create the context next to be able to use it in your components. To create a context you can use React.createContext passing it the default value for that context.

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.

In the src directory, create the file UserContext.js with the following content:

import React from "react";

const UserContext = React.createContext({
  user: null,
  setUser: () => {}
});

export default UserContext;

This will create a context having as a default value an object that has the property user, which by default is null, and a property setUser, which by default is a function that does nothing. You also need to export the context to use it in components.

Using the Context Provider

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.

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.

In this tutorial, you will put the provider in the App component which will render all the routes in the App.

Change the content of src/App.js to the following:

import 'bootstrap/dist/css/bootstrap.min.css';
import { useState } from 'react';

function App() {
    const [user, setUser] = useState(null);
    
    return (
    <UserContext.Provider value={{
      user,
      setUser
    }}>
    </UserContext.Provider>
  );
}

export default App;

First, you import the stylesheet for Bootstrap. This is for styling reasons only.

Then, inside the App component, you first define a user state variable and set its initial value to null.

In the returned JSX, you use the UserContext.Provider component. This is the context provider of UserContext. Every context created with React.createContext has this provider.

The provider takes a prop value, which is the value of the context. You pass it the user state variable created earlier and the setUser function to change the user state variable. This means that when other components use setUser function, the user state variable will change to the new value everywhere it's used.

Add Navigation Component

You'll now add the Navigation component. This Navigation component will show the Log In link when user is null, and will show the Log Out link when the user is not null.

Create the file src/components/Navigation.js with the following content:

import { useContext } from "react";
import { Container, Nav, Navbar } from "react-bootstrap";
import { Link } from "react-router-dom";
import UserContext from "../UserContext";

export default function Navigation () {
  const {user, setUser} = useContext(UserContext);

  function logout () {
    setUser(null);
  }

  return (
    <Navbar bg="light" expand="lg">
      <Container>
        <Navbar.Brand href="/">React Context</Navbar.Brand>
        <Navbar.Toggle aria-controls="basic-navbar-nav" />
        <Navbar.Collapse id="basic-navbar-nav">
          <Nav className="me-auto">
            {!user && <Link to="/login">Log In</Link>}
            {user && <Nav.Link href="#" onClick={logout}>Log Out</Nav.Link>}
          </Nav>
        </Navbar.Collapse>
      </Container>
    </Navbar>
  );
}

Notice the usage of useContext. 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 UserContext.Providers, including all of their children elements recursively, can use useContext to get the value of the context.

Here, you use useContext passing it the UserContext context to retrieve the user variable and setUser function. Then, based on the value of user you either show or hide the login and log-out links.

Notice the logout function, which is a handler of the onClick event of the log-out link. This function uses setUser to change the value of user to null, which will change the value everywhere it's being used or consumed.

Add Home Page

Next, you'll create the Home component which will show on the Home page. This component does nothing special. It just shows the Navigation component and shows the user a message based on whether they're logged in or not.

Create src/pages/Home.js with the following content:

import { useContext } from "react";
import { Container } from "react-bootstrap";
import Navigation from "../components/Navigation";
import UserContext from "../UserContext";

export default function Home () {
  const {user} = useContext(UserContext);
  return (
    <>
      <Navigation />
      <Container>
        {!user && <h1>You're not logged in</h1>}
        {user && <h1>You're logged in with {user.token}</h1>}
      </Container>
    </>
  );
}

Here you also use the useContext hook to retrieve the user. Notice that you are only retrieving the  user and not setUser because you won't need it here.

If the user is null, the message "You're not logged in" will show, else the message "You're logged in with {user.token}" will show. The value of user here will change when any consumer of the context uses setUser to change the value.

Add Home Route

After you've created the Home component, it's time to show it.

In src/App.js add the import for the Home component as well as the imports needed for routing from react-router-dom at the top of the file:

import {
  BrowserRouter as Router,
  Switch,
  Route
} from "react-router-dom";
import Home from './pages/Home';

Then, change the returned JSX to the following:

return (
    <UserContext.Provider value={{
    user,
    setUser
    }}>
    	<Router>
    		<Switch>
    			<Route path="/" component={Home} />
            </Switch>
		</Router>
	</UserContext.Provider>
);

Now, the Home component is a child of UserContext.Provider and subsequently it can access the context with its children using useContext.

If you run the server now:

npm start

You'll see a home page showing you that you're not logged in.

React Context Tutorial For Beginners

Add Login Page

Now, you'll add the login page which will allow the users to log in. To simulate the login process, you'll use Reqres, a fake REST API that lets you simulate a lot of requests including the user login request.

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.

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.

Create the file src/pages/LogIn.js with the following content:

import axios from "axios";
import { useContext, useEffect, useRef, useState } from "react";
import { Form, Button } from "react-bootstrap";
import { useHistory } from "react-router";
import Navigation from "../components/Navigation";
import UserContext from "../UserContext";


export default function LogIn () {
  const [email, setEmail] = useState("george.bluth@reqres.in");
  const [password, setPassword] = useState("");
  const {user, setUser} = useContext(UserContext);
  const history = useHistory();
  const buttonRef = useRef(null);

  useEffect(() => {
    //check if user is logged in or not
    if (user !== null) {
      //redirect home
      history.push('/');
    }
  }, [history, user]);

  function handleSubmit (event) {
    event.preventDefault();
    buttonRef.current.disabled = true;
    
    //login user
    axios.post('https://reqres.in/api/login', {email, password})
    .then(({data}) => {
      //set token in local storage
      setUser({
        email,
        password,
        token: data.token
      });
    })
    .catch((err) => {
      console.error(err);
      alert('An error occurred, please try again later.');
      buttonRef.current.disabled = false;
    })
  }

  return (
    <>
      <Navigation />
      <Form onSubmit={handleSubmit} className="w-75 mx-auto">
        <h1>Log In</h1>
        <Form.Group className="mb-3" controlId="formBasicEmail">
          <Form.Label>Email address</Form.Label>
          <Form.Control type="email" placeholder="Enter email" required value={email} onChange={(event) => setEmail(event.target.value)} />
        </Form.Group>

        <Form.Group className="mb-3" controlId="formBasicPassword">
          <Form.Label>Password</Form.Label>
          <Form.Control type="password" placeholder="Password" required value={password} onChange={(event) => setPassword(event.target.value)} />
        </Form.Group>
        <Button variant="primary" type="submit" ref={buttonRef}>
          Submit
        </Button>
      </Form>
    </>
  )
}

Just as explained above, you have the email and password state variables to make the form inputs controlled components. Notice that the initial value of email is one of the emails for users available in Reqres.

You retrieve user and setUser from the context using useContext. You also use useHistory which is a React Router hook to get access to the history instance which you'll use to navigate.

In useEffect, which will run whenever the user or history 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 history.

Inside handleSubmit, 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 setUser to set the user. Otherwise, you show an error.

The last thing left is to add the LogIn page as a route in src/App.js:

return (
    <UserContext.Provider value={{
    user,
    setUser
    }}>
    	<Router>
    		<Switch>
    			<Route path="/login" component={LogIn} />
        		<Route path="/" component={Home} />
            </Switch>
		</Router>
	</UserContext.Provider>
);

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.

React Context Tutorial For Beginners

You can enter any password you want then click Submit. 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.

React Context Tutorial For Beginners

Notice that the link in the navigation bar changed to show "Log Out" instead of "Log In". This is because the user variable passed through the context is updated everywhere it's being consumed. If you click on Log Out, the user variable will be null again.

Use Cookies

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 user state variable based on it.

In src/App.js add the following import at the beginning of the file:

import { useCookies } from 'react-cookie';

Then, change the definition of the user state to the following:

const [cookies] = useCookies();
const [user, setUser] = useState(cookies.token ? {token: cookies.token} : null);

The library react-cookie exposes the useCookies hook. Using this hook, you can retrieve the cookies object of cookies, where the properties are the name of each cookie.

If the cookie token is found, you set the initial value of user to the object {token: cookies.token}, else set it to null.

The next step is to set the cookie on login. In src/pages/LogIn.js add the import at the beginning of the file:

import { useCookies } from "react-cookie";

Then, change setUser in the fulfilment callback for the login request to the following:

setCookie('token', data.token);
setUser({
    email,
    password,
    token: data.token
});

The last step is to remove the cookie on log out. In src/components/Navigation.js add the import at the beginning of the file:

import { useCookies } from "react-cookie";

Then, inside logout function add the following line:

removeCookie('token');

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.

Conclusion

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.

]]>
<![CDATA[Get started with Medusa Part 2: Make the Server Your Own]]>https://dev.to/medusajs/get-started-with-medusa-part-2-make-the-server-your-own-gkaGhost__Post__6189441453259e060be115dbMon, 08 Nov 2021 15:46:13 GMT

In the first part of this tutorial series, I compared Medusa and Shopify to showcase how Medusa is the open-source alternative to Shopify. 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.

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.

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.

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.

The code for this tutorial is on this GitHub repository.

Prerequisites

This tutorial assumes you have already read and followed along with part 1. 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.

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 install it.

Add a Service

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.

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.

So, in this tutorial, you will create a service TopProductsService 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.

To create a service, start by creating the file src/services/top-products.jswith the following content:

import { BaseService } from "Medusa-interfaces";

class TopProductsService extends BaseService {
  constructor({ productService, orderService }) {
    super();
    this.productService_ = productService;
    this.orderService_ = orderService;
  }
}

Here are a few things to note about this service:

  1. 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 top-product, so to access it in other places we use topProductsService.
  2. Similarly to how you will use this service, we inject as dependencies the productService and orderService in the constructor. When you create classes in Medusa, you can use dependency injection to get access to services.

Implement getTopProducts

The next step is to add the method getTopProducts to the TopProductsService class. This method will retrieve the products from the database, sort them by their number of sales, then return the top 5 products.

Inside TopProductsService class add the new method:

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);
}

You first use this.productService_ to retrieve the list of products. Notice that the list method can take 2 optional parameters. The first one specifies where conditions, and the second parameter specifies the relations on this products to retrieve.

Then, you sort the array with the sort Array method giving it a compare function. In the compare function, you compare the number of sales stored inside the metadata field. In Medusa, most entities have the metadata field which allows you to easily add custom attributes in the default entities for your purposes. Here, you use the metadata field to store the number of sales. You are also sorting the products descending.

Finally, you use the splice Array method to retrieve only the first 5 items.

Implement updateSales

Next, you will implement the updateSales method in the TopProductsService. This method receives an order ID as a parameter, then retrieves this order and loops over the items ordered. Then, the salesproperty inside metadata is incremented and the product is updated.

Add the new method in TopProductsService:

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 }
      });

    }
  }
}

You first use this.orderService_ to retrieve the order by its ID. The retrieve 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.

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 update method on this.productService_.

This service is now ready to update product sales numbers and retrieve products ordered based on their sales number.

Add an API Endpoint

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 src/api/index.js with the following content:

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;
}

Creating an endpoint is easy. You just need to export an Express Router. This router can hold as many routes as you want.

In this code, you add a new GET route at the endpoint /store/top-products. The reason you are using store here as a prefix to top-products is that Medusa prefixes all storefront endpoints with /store, and all admin endpoints with /admin. You do not need to add this prefix, but it is good to follow the conventions of the Medusa APIs.

In this route, you retrieve the service you created in the previous section with this line:

const topProductsService = req.scope.resolve("topProductsService")

You can retrieve any service inside routes using req.scope.resolve. As explained in the services section, you need to use the camel-case version of the file name followed by Service when referencing a service in your code.

After retrieving the service, you can then use the methods you created on it. So, you return a JSON response that has the key products and the value will be the array of top products returned by getTopProducts.

Let us test it out. You can access this endpoint at localhost:9000/store/top-products. As this is a GET request, you can do it from your browser or using a client like Postman or Thunder Client.

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.

Get started with Medusa Part 2: Make the Server Your Own

Add a Subscriber

Finally, you will add a subscriber which will update the sales number of products when an order is placed.

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:

redis-cli ping

If the command returns “PONG” then the Redis service is running.

Then, go to Medusa-config.js 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:

// redis_url: REDIS_URL,

Remove the comments. This uses the variable REDIS_URL declared in the beginning of the file. Its value is either the Redis URL set in .env or the default Redis URL redis://localhost:6379. If you have a different Redis URL, add the new variable REDIS_URL in .env with the URL.

Then, restart the server. This will take the updated configuration and connect to your Redis server.

Now, you will implement the subscriber. Create the file src/subscribers/top-products.js with the following content:

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;

Similar to how you implemented TopProductsService, you pass the topProductsService in the constructor using dependency injection. You also pass eventBusService. This is used to subscribe a handler to an event in the constructor.

You subscribe to the order placed event with this line:

eventBusService.subscribe("order.placed", this.handleTopProducts);

The subscribe method on eventBusService takes the name of the event as the first parameter and the handler as the second parameter.

You then define in the class the handleTopProducts method which will handle the order.placed event. Event handlers in Medusa generally receive a dataobject that holds an id property with the ID of the entity this event is related to. So, you pass this ID into the updateSales method on this.topProductsService_ to update the number of sales for each of the products in the order.

Test It Out

You will now test everything out. Make sure the server is running. If not, run it with the following command:

npm start

Then, go to the Medusa storefront installation and run:

npm run dev

Go to the storefront and place an order. This will trigger the TopProductsSubscriber which will update the sales of the products in that order.

Now, send a request to /store/top-products like you did before. You should see that sales inside the metadata property of the products in that order has increased.

Get started with Medusa Part 2: Make the Server Your Own

Try to add a new product from the admin panel or use the database in the GitHub repository 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.

Conclusion

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.

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.

In the meantime, should you have any issues or questions related to Medusa, then feel free to reach out to the Medusa team via Discord.

]]>
<![CDATA[Get started with Medusa Part 1: the open-source alternative to Shopify]]>https://dev.to/medusajs/get-started-with-medusa-the-open-source-alternative-to-shopify-305jGhost__Post__617563116e5b3510767b3b9bTue, 02 Nov 2021 15:56:55 GMT

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.

Medusa 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.

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.

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.

Why Medusa

Customization Abilities

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.

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.

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 PostgreSQL and Redis.

For the frontend, you have the option to use a starter storefront built with either Next.js or Gatsby. 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.

As for the backend, it is also built with Gatsby and connects to your server just like the frontend.

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.

Suggested Read: Medusa: Create A Fast and Highly Customizable E-Commerce Store

Pricing

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.

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.

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.

Business Use Cases

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.

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.

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.

Prerequisites

Before we start, make sure you install Node.js if you have not. You will also need NPM but it will install with Node.js when you install it.

To check if you have Node.js and NPM installed you can run these commands:

node -v
npm -v

If the output of each of the commands shows a number version, then you have them installed. Otherwise, you need to install them.

Set Up Medusa

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.

Install Medusa

Installing Medusa is easy. First, you need to install the CLI tool that allows you to set up the server:

npm install -g @medusajs/medusa-cli

Once this part is done, you can use the CLI to set up a new Medusa store on your machine:

medusa new my-store --seed

This will create a new Medusa installation in the directory my-store. You can change the name of the store or directory by changing my-store. By applying the --seed option, it will seed the database with basic data including a demo product.

Run Medusa

Once this command is done, you are ready to run your server! First, change to the directory of the medusa store:

cd my-store

Then, run the develop command using the CLI tool to run the server:

medusa develop

This will run the server by default at localhost:9000. You can test it by going to localhost:9000/store/products in your browser and you should see a JSON array of products. It will include just one product as the seeder adds just one.

You can check the full list of API endpoints in the documentation. For the storefront, all endpoints are prefixed with /store, whereas for the admin panel, all endpoints are prefixed with /admin.

Structure Overview

Let's take a look at the directory structure for the server. It should look something like this:

As you can see we have the following directories:

Get started with Medusa Part 1: the open-source alternative to Shopify
  1. data: This directory holds the data that will be used to seed the database. It has the file seed.json which includes the configuration for the basic store. These data are the data added to your store when you add the --seed option which we did.
  2. dist: This directory will hold the build of your server when you run npm run build. When you deploy your server you will run this command and the compiled files in the dist directory will be used.
  3. src: Inside the src directory you can add any of the plugins or changes you might need to make. Inside the api subdirectory, you can add new endpoints to your store. Inside the services subdirectory, you can add new services which you can use globally in different endpoints. Inside the subscribers subdirectory, you can add event listeners to different events like when an order is placed.
  4. uploads: will include any files to be uploaded like product images.

Set Up the Storefront

Next, we'll install and set up the storefront. As mentioned earlier, you can use the Gatsby starter or Next.js starter. For this tutorial, we'll use the Next.js starter.

Install the Storefront

To install the Next.js storefront just run the following command:

npx create-next-app -e https://github.com/medusajs/nextjs-starter-medusa my-storefront

This will create a Next.js storefront in the directory my-storefront. If you to name it something else you can change the name in the command.

Run the Storefront

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.

To run the storefront, first change to the directory of the storefront:

cd my-storefront

Then, run the following command to run the storefront:

npm run dev

This will run the storefront at localhost:8000 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.

Get started with Medusa Part 1: the open-source alternative to Shopify

Add Stripe Integration

To add the Stripe integration, first copy the .env.template to .env.local:

mv .env.template .env.local

Then, change the environment variable for Stripe's public key:

NEXT_PUBLIC_STRIPE_KEY=pk_test_something

Structure Overview

The structure of the directory should look like this:

Get started with Medusa Part 1: the open-source alternative to Shopify
  1. components: 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.
  2. context: 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 context/display-context.js by changing the value of cartView in the defaultDisplayContext object.
  3. pages: 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.
  4. public: You can add the public assets like images here.
  5. styles: This directory holds all the styles of the store and you can make changes here to change the styles of the storefront.
  6. utils: This includes helper functions like getting Stripe's public key, helper functions, configurations, and more.

Set Up the Admin Panel

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.

Install the Admin Panel

To set up the admin panel, first, clone the repository of the admin panel:

git clone https://github.com/medusajs/admin my-admin

Then, change to the directory of the admin panel, which is my-admin. You can change that by changing it in the command above.

cd my-admin

After that, you need to install the dependencies with NPM:

npm install

Run the Admin Panel

Once all the dependencies are installed, we're ready to run the admin panel:

npm start

This will open the admin panel at localhost:7000 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".

When you log in, you will see an admin panel with a sidebar that you can use to view orders, customers, products, and more.

Get started with Medusa Part 1: the open-source alternative to Shopify

Structure Overview

The structure of the directory should look something like this:

Get started with Medusa Part 1: the open-source alternative to Shopify
  1. src: 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.
  2. public: This will include the build generated by Gatsby for the admin panel.
  3. static: The public static assets you will need for the admin panel like images.

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.

Alternative Solution: Create Medusa App

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.

Medusa introduces create-medusa-app. If you've used React before, you will notice that this is similar to create-react-app. by using this tool, you will be able to set up the 3 components of the platform all at once.

Set Up Medusa App

In your terminal, you just need to run the following command:

npx create-medusa-app

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.

Once the installation is done, you will have 3 directories ready. One for the server which will be called backend, one for the storefront which will be called storefront, and one for the admin which will be called admin.

Run the Medusa App

Similar to the instructions of each component in the first method, when we install them separately, you will have to run each component separately.

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.

To run the Medusa server you need to change to the backend directory then run it:

cd backend
npm start

To run the Medusa storefront you need to change to the storefront directory then run it:

cd storefront
npm start

To run the Medusa admin you need to change to the admin directory then run it:

cd admin
npm start

Conclusion

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.

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.

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 their Discord!

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.

]]>
<![CDATA[Strapi Tutorial: Build a Blog with Next.js]]>https://blog.shahednasser.com/strapi-tutorial-build-a-blog-with-next-js/Ghost__Post__617a615c7ec5e905d9bde6dbMon, 01 Nov 2021 10:13:21 GMT

If you want to start your own blog, or just want to learn a cool CMS platform, then you should check out Strapi. 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.

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.

Why Strapi

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.

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.

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.

Set Up Strapi

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.

Install Strapi

The first step is to install Strapi. You can do that with this command:

npx create-strapi-app strapi-blog --quickstart

Register as Admin

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.

Strapi Tutorial: Build a Blog with Next.js

Once you're done, you'll be logged into your dashboard.

Create a Content-Type

Let's say you're creating the blog's database yourself. You'll need to create a posts table that stores all the posts you'll create.

In Strapi, you create Content-Types. In these Content-Types, you can add any kind of field you would to the table.

On your dashboard, you should see "Create Your First Content-Type". Click on it.

Strapi Tutorial: Build a Blog with Next.js

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 post in the Display Name field then click Continue.

After that, you'll need to add some fields to the Content-Type. You'll see that there are many to choose from.

Add the following fields to the Post Content-Type:

  1. title of type Text. You can set it to required by clicking on the Advanced Settings Tab and checking the required checkbox.
  2. content of type Rich text. You should also set it to required.
  3. admin_user this will be a Relation type. You'll link it to the User Content-Type.
  4. date_created this will be a Date field of type Datetime. You can also set it to required.
  5. file this will be a Relation type as well to the File Content-Type. We can use it to add an image to the post

Once done, the Post Content-Type should look like this:

Strapi Tutorial: Build a Blog with Next.js

Click Save, and the new Content-Type will be added successfully.

Set Permissions

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.

Strapi Tutorial: Build a Blog with Next.js

There, choose Public, then scroll down to Permissions and select all permissions.

Making Requests

If you now try sending a GET request to localhost:1337/posts you'll see an empty array.

In Strapi, once you create a Content-Type, you'll have the following API requests ready for use:

  1. GET /posts: Get the list of items in the Content-Type.
  2. GET /posts/{id}: Get the item having id {id}.
  3. GET /posts/count: Get the number of items in the Content-Type.
  4. POST /posts: Create a new post.
  5. DELETE /posts/{id}: Delete a post of id {id}.
  6. PUT /posts/{id}: Update a post of id {id}.

Note that we use the plural form of the Content-Type in the requests.

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.

Using Strapi Starters

There are many starters 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.

In this section, you'll create a blog using Strapi starters. We'll use Next.js for the front-end.

Set Up Next.js Starter

To create a Strapi blog with Next.js, you can use strapi-starter-next-blog. It comes with both a Strapi installation ready with the necessary Content-Types which are Article and Category.

In your terminal run the following command to install it:

npx create-strapi-starter strapi-next-blog next-blog

This will install inside a directory called strapi-next-blog 2 directories. One called backend, which includes the Strapi installation, and one called frontend, which includes the Next.js installation.

Once the installation is done, change to the frontend directory then run both Strapi and Next.js with one command:

npm run develop

This will run Strapi on localhost:1337 and Next.js on localhost:3000.

If the browser was not opened with to the Strapi dashboard, go to localhost:1337/admin/auth/register-admin and register as a new user just like you did before.

When you are redirected to the dashboard, you'll see that there are already Content-Types and Collections for these types ready.

Strapi Tutorial: Build a Blog with Next.js

If you go to each of them you'll see that there are already demo data available.

Now, to check the frontend, go to localhost:3000. You'll see a blog with some blog posts ready.

Strapi Tutorial: Build a Blog with Next.js

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.

Conclusion

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.

After following along with this tutorial, you should check out more of Strapi's Content API documentation to learn more about how you can access the content types and more.

]]>
<![CDATA[Why Video Marketing Is So Powerful In 2021]]>https://blog.shahednasser.com/why-video-marketing-is-so-powerful-in-2021/Ghost__Post__617b981e7ec5e905d9bde7c0Fri, 29 Oct 2021 06:47:56 GMT

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 marketing technique 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.

Why is Video Marketing Powerful?

Finding the answers to the above questions helps formulate an effective video advertising plan 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:

Boost Sales and Increase Conversions

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?

Sense of Physical Existence

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.

Video provides great ROI

Many businesses feel that video content generates a great ROI. There are various video editor 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!

Because Google Loves Videos

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.

Video Marketing Explains Everything

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!

Mobile Users Enjoys Video

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.

Video Engage the Lazy Buyers

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.

Move-in Before your Competitor

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.

Create a killer video using your favorite video editor 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.

Video Marketing Available Everywhere and Every time

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.

Animated Video Ads

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.

Conclusion

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.

]]>
<![CDATA[Knex.js Tutorial For Beginners]]>https://blog.shahednasser.com/knex-js-tutorial-for-beginners/Ghost__Post__617844cc6e5b3510767b3db0Thu, 28 Oct 2021 11:54:53 GMT

Knex.js 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.

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.

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.

You can find the code for this tutorial in this GitHub repository.

Prerequisites

Before we start, make sure you have Node.js installed along with NPM. NPM is installed with Node.js by default, so you just need to install Node.js

To check if you have it installed, run the following commands:

node -v
npm -v

If the output is a version, then they're installed on your machine.

Set Up Project

The first step is to set up the project. Open a terminal and create a directory to place the project inside:

mkdir knex-tutorial

Then change to that directory:

cd knex-tutorial

Once inside the directory, run the following command to initialize the project with NPM:

npm init -y

The option -y is added to fill the generated package.json with default values.

The next step is to install the dependencies needed for this tutorial:

npm i express body-parser knex nodemon

With the command above you'll install Express, which is what we'll use to build the server; body-parser, which is used in Express to parse body parameters; knex for Knex.js; and nodemon, which is used to watch changes and restart the server.

Now, create the file index.js in the root and add the following content in it:

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
app.use(bodyParser.json());

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

This will create a simple server with Express.

Finally, add the start script in scripts in package.json:

"scripts": {
    "start": "NODE_ENV=development nodemon index.js"
},

Now, you can run the server with the following command:

npm start

You can test the server by going to localhost:3000. You should see "Hello, World".

Set Up Knex.js

In this section, you'll set up and configure Knex.js.

Knex.js has a CLI you can use to create migrations, seeders, and more. So, start by installing it globally:

npm i -g knex

After the installation is done, you can start making use of the CLI.

The first step in initializing Knex.js is to create the knexfile. The knexfile is a file that contains the configuration for Knex.js, including which database client to use for each environment and the connection configuration.

Create the db directory which will hold all files related to the database setup:

mkdir db

Then, change to the db directory:

cd db

Inside the directory, run the following command to create knexfile.js:

knex init

This will create knexfile.js with the following content:

// Update with your config settings.

module.exports = {

  development: {
    client: 'sqlite3',
    connection: {
      filename: './dev.sqlite3'
    }
  },

  staging: {
    client: 'postgresql',
    connection: {
      database: 'my_db',
      user:     'username',
      password: 'password'
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: 'knex_migrations'
    }
  },

  production: {
    client: 'postgresql',
    connection: {
      database: 'my_db',
      user:     'username',
      password: 'password'
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: 'knex_migrations'
    }
  }
    
};

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.

In this tutorial, we'll just cover setting up the development environment using SQLite. However, if you are interested in setting up another DB management system, you can follow along but refer to Knex.js's documentation to understand how you should set up your connection to your database.

Replace the content of knexfile.js with the following:

const path = require('path');
// Update with your config settings.

module.exports = {

  development: {
    client: 'sqlite3',
    connection: {
      filename: path.join(__dirname, 'db.sqlite3')
    },
    migrations: {
      tableName: 'knex_migrations'
    },
    useNullAsDefault: true
  }

};

This will use sqlite3 for the development environment. Unlike other DB management systems, you just need to specify the file name for SQLite.

This configuration also specifies that the database should have a table called knex_migrations to keep track of the migrations. As for useNullAsDefault, it's necessary for SQLite configuration if you have columns that you want to default to Null.

As you are using sqlite3, you need to install its library:

npm install sqlite3

If you're using another DB management system, then you need to install its library instead.

Finally, go back to index.js in the root and add the following to add the configuration when the server runs:

const knexConfig = require('./db/knexfile');
//initialize knex
const knex = require('knex')(knexConfig[process.env.NODE_ENV])

This initializes knex based on the current environment.

Create a Migration

Migration allows you to easily modify a database schema. Inside each migration, you'll have 2 functions: up is executed when the migration runs, whereas down is executed the migration is rolled back. This means when you don't need the changes that were done by the migration anymore.

Before you create a migration, make sure you're still in the db directory.

Then, inside that directory run:

knex migrate:make create_users_table

This will create a migration file inside a directory that knex will create called migrations. If you open it, you'll see that there are already up and down functions.

Replace the content of the file with the following:


exports.up = function(knex) {
  return knex.schema
    .createTable('users', function (table) {
      table.increments('id');
      table.string('name', 255).notNullable();
      table.string('email', 255);
      table.timestamps();
    });
};

exports.down = function(knex) {
  return knex.schema
    .dropTable('users');
};

Inside the up function, a new table called users is created. The table has an auto-increment column id, string columns name and email, and timestamp columns which by default are created_at and updated_at.

Inside the down function, the table is dropped. This means that when you don't want the users table anymore, you just rollback the migration.

Now, go to package.json in the root of the project and the migrate script inside scripts:

"migrate": "knex migrate:latest --knexfile db/knexfile.js"

This script uses Knex's CLI command migrate:latest to migrate the latest migrations that have not been migrated yet. The option --knexfile specifies the location of the knexfile.

Now, change back to the root directory of the project. Then, run the following command:

npm run migrate

This will create a new SQLite database db/db.sqlite3, then using the migration you created earlier creates the users table.

You can check this if you have an SQLite viewer. I use DB Browser for SQLite.

You'll see that the database has the users table with the columns you added in the up function.

Knex.js Tutorial For Beginners

Create a Seed

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.

To create a seed file, run the following command:

knex seed:make users --knexfile db/knexfile.js

This will create the seed file users.js inside db/seeds. The knexfile option specifies the location of knexfile.js.

If you open db/seed/users.js, you'll see the function seed. This function first deletes all current users in the database then adds new ones.

Replace the content of the file with the following:

exports.seed = function(knex) {
  // Deletes ALL existing entries
  return knex('users').del()
    .then(function () {
      // Inserts seed entries
      return knex('users').insert([
        {id: 1, name: 'Hettie Marshall', email: 'lantunde@acbo.va'},
        {id: 2, name: 'Hester Owens', email: 'zo@girih.lv'},
        {id: 3, name: 'Henry Jackson', email: 'bekamohi@owo.mt'}
      ]);
    });
};

Now this function inserts 3 users into the users table.

Now, add the seed command to package.json:

"seed": "knex seed:run --knexfile db/knexfile.js"

Then, run the command:

npm run seed

This will add the 3 users to the database. You can use the SQLite viewer again to check it.

Knex.js Tutorial For Beginners

Read Data with Knex.js

In this section, you'll create a GET endpoint to retrieve users. You'll use Knex.js to retrieve the users.

In index.js add the new route:

app.get('/user', (req, res) => {
    // TODO get users
})

To retrieve data from the database using Knex.js, you first use knex(<TABLE_NAME>) to access the table, then use the method select to specify which columns you want to retrieve.

Finally, to use the retrieved data you can either use a Promise or a callback.

Add the following inside the callback function for the newly created route:

knex('users')
  .select({
    id: 'id',
    name: 'name'
  })
  .then((users) => {
    return res.json(users);
  })
  .catch((err) => {
    console.error(err);
    return res.json({success: false, message: 'An error occurred, please try again later.'});
  })

This accesses the table users with knex, then selects id and name. Inside then's fulfillment handler returns a JSON response with the users array. catch handles any errors that might occur.

Let's test it out! If you don't have the server running make sure to run it again:

npm start

Then, send a GET request to localhost:3000/user. You will receive an array of users.

Knex.js Tutorial For Beginners

Insert Data with Knex.js

In this section, you'll learn how to insert data in the database using Knex.

Create a new POST route that allows us to add a new user:

app.post('/user', (req, res) => {
    // TODO insert user
});

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 insert method on knex to insert new data.

Add the following inside the callback function of the route:

const name = req.body.name ? req.body.name : '';
const email = req.body.email ? req.body.email : '';

if (!name) {
    return res.json({success: false, message: 'Name is required'});
}

knex('users')
    .insert({name, email})
    .then((id) => {
    //get user by id
    knex('users')
        .select({
        id: 'id',
        name: 'name'
    })
        .where({id})
        .then((user) => {
        return res.json(user[0]);
    })
})
    .catch((err) => {
    console.error(err);
    return res.json({success: false, message: 'An error occurred, please try again later.'});
});

This first get name and email from the body of the request. If name isn't found then it returns an error.

If all is good, a new user will be inserted. Then, inside the fulfillment handler then, you receive as a parameter the id of the newly added user. Use it to retrieve the user and return it.

Now, send a POST request to localhost:3000/user and in the body add a name and email parameter. The new user will be inserted and returned in the request.

Knex.js Tutorial For Beginners

Conclusion

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.

Make sure to read the Knex.js documentation to learn more about how to use it in your projects.

]]>
<![CDATA[On Edge Between SEO and Design]]>https://blog.shahednasser.com/on-edge-between-seo-and-design/Ghost__Post__6176bca56e5b3510767b3d92Mon, 25 Oct 2021 14:24:52 GMT

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.

Combining SEO and design is the best way to rank better on the search engine results page(SERPS). A poor bad graphic design squander the organic equity.

Importance of Web Design in SEO website navigation

You may wonder: why is design important? 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.

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.

Through clear navigation, 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.

It's hard for web crawlers to locate important pages on incomplete and overcrowded navigation systems. Similarly, poor navigation systems dilute link equity.

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.

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.

Tips to Achieve Clear navigation on Your Site

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.

The website navigation is like your visitor's roadmap. Typically, you are providing direction on where to go. How do you achieve clear navigation?

  • Put your navigation menu at the top of the page, and it should lead in the right direction.
  • 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.
  • Use simple terminologies in the main menu, i.e., avoid technical jargons
  • Use Subpages/Sub-navigation to breakdown navigation choices. Use SEO
  • Add a search bar for visitors to quickly locate a page of interest
  • Ensure each page URL is clear, concise, and descriptive
  • The main menu must be accessible to smaller mobile devices

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 website design service can help you fix it.

Which Content Strategy? is Less More, or is More Better?

Less content grabs attention, but a longer message informs the reader.

Less is More.

The attention span for website users is about 7 seconds. When web pages take a long time to load, the bounce rate is higher.

Shorter is preferable when:

  • Your target is the general public
  • Your audience is familiar with a service/product
  • Your service/product is straightforward

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.

500-word blog posts, 30-second video ads, and micro-content, e.g., tweets and status updates,perform well on smartphones.

Sadly, short content has a short life span. Therefore, you need to produce them constantly.

Shorter is beneficial in:

  • Generating traffic
  • Increasing click-through rates
  • Generating qualified leads.
  • Previewing long-form content

Long-Form content

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., offermore knowledge. According to BackLinko, longer articles have more social media shares than shorter articles.

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.

Indexable Pages Appear on SERPs

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.

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.

Gathered information from web crawlers flows back to the search engines offering more knowledge 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.

Therefore, indexable 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.

Optimize Product and Website Images for Better Ranking

Images are a bigger part of the design and visual communications. 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.

Over 85%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:

  • 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.
  • 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.
  • 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.
  • Image file names – name the files using words that describe them accurately and clearly, e.g., running shoes and not image 01.

Conclusion

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 website only shows text. 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.

]]>
<![CDATA[How to Animate Components' Entrance and Exit in React]]>https://blog.shahednasser.com/how-to-animate-components-entrance-and-exit-in-react/Ghost__Post__61705ebc6e5b3510767b39abThu, 21 Oct 2021 10:26:43 GMT

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.

In this tutorial, we'll cover how to animate components' entrance and exit in React using React Transition Group.

You can find the full code for this tutorial in this GitHub Repository, and you can see a working demo.

What is React Transition Group

React Transition Group is a library that allows you to add animation on a component or multiple components' entrance and exit.

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.

React Transition Group exposes the components that will allow you to easily do that. There are 4 components that it exposes: Transition, CSSTransition, SwitchTransition, and TransitionGroup.

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.

Animating a Single Element

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.

There are 2 components we can use: Transition and CSSTransition. The recommended component is CSSTransition, but we'll cover both.

Using Transition

With the Transition component, you can add CSS styling based on the different states. This component covers the states:

  1. entering: Before the element enters.
  2. entered: Element has entered.
  3. exiting: Before the element exits
  4. exited: The element has exited.

Generally, CSSTransition is recommended to be used instead of Transition. Transition is provided as a platform-agnostic base component.

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.

const [transitionState, setTransitionState] = useState(false)

Then, We'll use the Transition component to wrap the img element. The Transition component takes the prop in which is a boolean variable that indicates whether the component should enter or not. We should pass the state variable to this prop.

Another required prop that Transition accepts is timeout which defines the duration of the animation.

<Transition in={transitionState} timeout={300} >
...
</Transition

Inside Transition, a function is passed which receives the state parameter. This parameter indicates the current state of the component, which will be one of the 4 states mentioned earlier.

Using that state variable we can change the CSS styling of the component to animate it.

So, we need to create an object that holds the stylings we want to apply:

const transitions = {
  entering: {
    display: 'block'
  },
  entered: {
    opacity: 1,
    display: 'block'
  },
  exiting: {
    opacity: 0,
    display: 'block'
  },
  exited: {
    opacity: '0',
    display: 'none'
  }
};

Notice how we set the object keys or properties as the name of the states.

Then, in the child function of Transition, we set the style based on the current state:

<Transition in={transitionState} timeout={300} >
	{state => (
		<img src="https://cataas.com/cat" alt="Cat" style={{
			transition: 'all .1s',
			opacity: 0,
			display: 'none',
			...transitions[state]
			}} className="mt-2" />
	)}
</Transition>

Notice how the function returns the img element. Inside the style prop of the img element we first set the default styling, then we add the styling based on the state using this line:

...transitions[state]

Now, everytime the state changes when the component enters or exits, the state variable in the child function will change. So, the styling of the element will change based on the value of the state variable, which will add animation to the element.

Also, the image we're using is from Cat as a service.

The only thing left is to add a button to toggle the state variable transitionState to show and hide the image:

<Button onClick={() => setTransitionState(!transitionState)}>{transitionState ? 'Hide' : 'Show'} Cat</Button>

Using CSSTransition

The recommended approach for this use case is using CSSTransition. The CSSTransition component allows you to add classes for each state, which gives you more freedom to add animation to your components.

To make the animation easier we'll use Animate.css which is a CSS animation library that provides us with many animations we can easily use.

To animate an element with CSSTransition, you wrap it within the CSSTransition component. Similar to Transition CSSTransition receives the in prop which indicates whether the component should enter or exit. Also, it accepts the timeout prop which determines the duration of the animation.

Unlike Transition, CSSTransition receives the prop classNames which allows us to define the classes that should be added based on the different states.

classNames 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 classNames "fade", the class fade-enter will be added to the component when it enters. When the component exits, the class fade-exit is added. The same goes for the rest of the states.

If an object is passed as the value for classNames, 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:

classNames={{
 appear: 'fade-in',
 appearActive: 'fade-in-active',
 appearDone: 'fade-in-appeared',
 enter: 'fade-in-enter',
 enterActive: 'fade-in-enter-active',
 enterDone: 'fade-in-done',
 exit: 'fade-out',
 exitActive: 'fade-out-active',
 exitDone: 'fade-out-active',
}}

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 enterActive, and the class that you want to apply when the element exits to exitActive. Basically, the active phase of each state is when you should apply the animation.

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:

const [showCat, setShowCat] = useState(false);
const [imageClasses, setImageClasses] = useState("d-none");

showCat will be used for the in prop to determine when the element should enter and exit. As for imageClasses, we'll get to why we need it later on.

Next, we'll add the CSSTransition component:

<CSSTransition in={showCat} timeout={500} classNames={{
          enterActive: 'animate__bounceIn',
          exitActive: 'animate__bounceOut'
        }} 
        onEnter={showImage}
        onEntered={removeOpacity}
        onExited={hideImage}
        className={`animate__animated my-4 ${imageClasses}`}>
...
</CSSTransition>

Notice the following:

  1. On enterActive, which is when the element should appear, we add the class animate__bounceIn, and on exitActive, which is when the element should exit, we add the class animate__bounceOut. Both these classes are from the Animate.css library.
  2. We have added a listener for onEnter, which will be triggered when the element enters; a listener for onEntered, which will be triggered when the element has finished entering; a listener for onExited which will be triggered when the element has exited. We'll implement these listeners in a bit.
  3. We have passed a className prop that would add default classes to the child component.

As you can see, we're using the state variable imageClasses inside the string passed to className. When using CSSTransition, you'll assume that the exit state will be applied initially when the initial value passed to in is false. That's actually not true. Initially, if the value of the in prop is false, no classes are added.

As we don't want the image to be initially visible, we're using a state variable to add the Bootstrap class d-none as we're using it in our project. This class will hide the element when added.

And this is why we added the event listeners. We'll change the value of imageClasses based on each state:

function hideImage() {
	setImageClasses("d-none");
}

function showImage(node) {
    setImageClasses("d-block");
    node.style.opacity = 0;
}

function removeOpacity (node) {
    node.style.opacity = 1;
}

Inside CSSTransition we add the element we want to animate:

<CSSTransition in={showCat} timeout={500} classNames={{
          enterActive: 'animate__bounceIn',
          exitActive: 'animate__bounceOut'
        }} 
        onEnter={showImage}
        onEntered={removeOpacity}
        onExited={hideImage}
        className={`animate__animated my-4 ${imageClasses}`}>
	<img src="https://cataas.com/cat" alt="Cat" />
</CSSTransition>

That's it! The only thing left is to add the button to toggle the showCat state variable:

<Button onClick={() => setShowCat(!showCat)}>{showCat ? 'Hide' : 'Show'} Cat</Button>

Now, every time you click the button the classes will change based on the state.

Animate a Group of Element

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 CSSTransition or Transition on them one by one.

Using TransitionGroup

The component TransitionGroup wraps a list of CSSTransition or Transition 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.

You pass CSSTransition or Transition components as children. There's no need to pass props to TransitionGroup, as the configuration for the animation is done through the props passed to the children components.

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.

How to Animate Components' Entrance and Exit in React

To make the implementation easier, we'll have an array of languages to add items from it randomly:

const defaultLanguages = [
  {
    id: 1,
    name: 'Java'
  },
  {
    id: 2,
    name: 'JavaScript'
  },
  {
    id: 3,
    name: 'PHP'
  },
  {
    id: 4,
    name: 'CSS'
  },
  {
    id: 5,
    name: 'C'
  },
  {
    id: 6,
    name: 'C#'
  },
  {
    id: 7,
    name: 'HTML'
  },
  {
    id: 8,
    name: 'Kotlin'
  },
  {
    id: 9,
    name: 'TypeScript'
  },
  {
    id: 10,
    name: 'Swift'
  }
];

And we'll use a one-liner function from 1Loc to get random elements from an array:

const randomItems = (arr, count) => arr.concat().reduce((p, _, __, arr) => (p[0] < count ? [p[0] + 1, p[1].concat(arr.splice((Math.random() * arr.length) | 0, 1))] : p), [0, []])[1];

Then, we'll define a state variable which will be the array of languages we'll show the user in a list:

const [languages, setLanguages] = useState(randomItems(defaultLanguages, 4));
const [counter, setCounter] = useState(11);

We also define a state variable counter which we'll use to change the id property from the defaultLanguages array when adding a new item to the languages array. This is just to ensure that the IDs are unique when we are choosing random items from the array.

Then, we render a TransitionGroup component and inside it we loop over the languages state variable and render a CSSTransition component for that variable:

<TransitionGroup>
	{languages.map(({id, name}) => (
		<CSSTransition key={id} classNames={{
                enterActive: 'animate__animated animate__lightSpeedInLeft',
                exitActive: 'animate__animated animate__lightSpeedOutLeft'
              }} timeout={900}>
			<li className="p-3 border mb-3 shadow-sm rounded border-info d-flex justify-content-between">
				<span>{name}</span>
                <CloseButton onClick={() => removeLanguage(id)}></CloseButton>
             </li>
			</CSSTransition>
	))}
</TransitionGroup>

Notice that we're passing the class animate__animated animate__lightSpeedInLeft for the state enterActive. As mentioned in the previous section, this class we'll be added when the element enters. We're also passing the class animate__animated animate__lightSpeedOutLeft for the state exitActive. As mentioned in the previous section, this class we'll be added when the element exits. Also we're passing the timeout prop with value 900.

Inside CSSTransition we pass the element we want to animate which is an li element. The element shows the name of the language and has a CloseButton component which on click should remove the language from the list. Please note that the CloseButton comes from the React Bootstrap which we're using just for styling purposes.

As you can see TransitionGroup is only used as a wrapper to these elements.

We also need to add a button to add languages:

<Button onClick={addLanguage}>Add</Button>

What's left is to implement the event listeners addLanguage and removeLanguage:

function addLanguage() {
    const newLanguages = languages.splice(0);
    const newItem = Object.assign({}, randomItems(defaultLanguages, 1)[0]);
    newItem.id = counter;
    newLanguages.push(newItem);
    setLanguages(newLanguages);
    setCounter(counter + 1);
}

function removeLanguage (id) {
    const newLanguages = languages.splice(0);
    const ind = newLanguages.findIndex((language) => language.id === id);
    if (ind !== -1) {
        newLanguages.splice(ind, 1);
        setLanguages(newLanguages);
    }
}

The addLanguage listener picks a random item from the array. We use Object.assign to clone the item from the array instead of getting the item by reference. We then change the id to make sure it's unique.

In the removeLanguage listener we just find the index of the language in the array and remove it.

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.

Applying Animation With a Switch

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 SwitchTransition component.

The SwitchTransition wraps a CSSTransition or Transition element. It accepts one prop mode which can be of two values: out-in or in-out, with out-in being the default. When choosing out-in, it means that the old state exits first then the new state enters. When choosing in-out it's the opposite; the new state enters then the old state exits.

When the state of the component changes, the component exits and a new component with the new state enters.

In this example, we'll have an Alert, which is a component exposed by React Bootstrap. We'll have a state that will toggle the variant, which is the background color and the theme of the Alert component, between danger and success. We'll also change the text of the Alert component based on the variant.

First, we'll define the state variable to toggle the state of the Alert component:

const [isDanger, setIsDanger] = useState(true);

Then, we'll render the SwitchTransition component which will take as a child a CSSTransition component to manage the animation of the Alert component:

<SwitchTransition mode="out-in">
    <CSSTransition key={isDanger} classNames={{
		enterActive: 'animate__animated animate__flipInX',
		exitActive: 'animate__animated animate__flipOutX'
 	}}
	timeout={500}>
		<Alert variant={isDanger ? 'danger' : 'success'}>{isDanger ? "You're in danger" : "Danger cleared"}</Alert>
	</CSSTransition>
</SwitchTransition>

As you can see we pass to SwitchTransition the mode out-in, but this is the default mode so it's optional to pass.

For CSSTransition we pass it the prop key which will be used to enter and exit elements based on the state. When the state variable isDanger changes, the component will be removed and a new one with the new value will be added. This key prop behaves exactly as it would when you render items from an array using map.

For the enterActive animation state, we add the class animate__animated animate__flipInX. For the exitActive animation sate, we add the class animate__animated animate__flipOutX.

As for the child of CSSTransition we pass the Alert component, which sets the variant and text based on the value of isDanger.

Finally, we'll render a button to toggle the value of isDanger:

<Button onClick={() => setIsDanger(!isDanger)}>
	{isDanger ? 'Clear Danger' : 'Bring Danger'}
</Button>

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 out-in.

If you try to change the mode to in-out, you'll see that when you click the button a new Alert will enter and then the old one will exit.

Conclusion

Adding animation to components provides a nice user experience and add a flair to your website.

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.

]]>
<![CDATA[10 Awesome Web Development Resources You Might Not Know]]>https://blog.shahednasser.com/10-awesome-web-development-resources-you-might-not-know/Ghost__Post__616af8d07a819fa97764d33fMon, 18 Oct 2021 14:14:41 GMT

Last year, I created the repository awesome-resources 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.

Some of these resources can be necessary basic knowledge including the documentation of a framework or courses for a programming language.

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.

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.

CSS

Style Stage from Modern CSS Solutions

10 Awesome Web Development Resources You Might Not Know

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 list of styles 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.

Grid and Flex Cheat Sheets by Chris Malven

10 Awesome Web Development Resources You Might Not Know

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.

Glassmorphism CSS Generator

10 Awesome Web Development Resources You Might Not Know

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.

Once you like the design, you can copy the CSS and HTML and use them on your website.

JavaScript

CoderslangJS

10 Awesome Web Development Resources You Might Not Know

CoderlangJS 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.

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.

JavaScript 30

10 Awesome Web Development Resources You Might Not Know

JavaScript 30 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.

Favorite JavaScript Utilities in Single Line of Code - 1LOC

10 Awesome Web Development Resources You Might Not Know

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.

JS.ORG

10 Awesome Web Development Resources You Might Not Know

JS.ORG 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.

So, if your repository is related to JavaScript, you can follow the steps on their website to get a free subdomain for your project.

React.js Cheat Sheet by devhints.io

10 Awesome Web Development Resources You Might Not Know

This cheat sheet is specifically for React created by devhints.io. It's a simple and to-the-point cheat sheet that is easily readable. It has information on components, lifecycle, hooks, and more.

Other

Web Accessibility Evaluation Tools List

10 Awesome Web Development Resources You Might Not Know

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 WebAccessibility.com and Color Contrast Accessibility Validator.

404 Illustrations

10 Awesome Web Development Resources You Might Not Know

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.

Bonus

This section includes resources that I found helpful but are not necessarily related to Web Development in particular.

List of Badges, in Markdown

10 Awesome Web Development Resources You Might Not Know

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.

GIT PURR! Git Commands Explained with Cats!

10 Awesome Web Development Resources You Might Not Know

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.

Machine Learning Roadmap 2020

10 Awesome Web Development Resources You Might Not Know

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.

Conclusion

Through creating the awsome-resources 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.

This list is just a small list of the resources found in the repository. 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.

]]>
<![CDATA[14 CSS Libraries You Should Check Out]]>https://blog.shahednasser.com/14-css-libraries-you-should-check-out/Ghost__Post__616598ad3eea8f060129b49cThu, 14 Oct 2021 10:44:08 GMT

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.

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.

NES.css

14 CSS Libraries You Should Check Out

NES.css 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.

Animate.css

14 CSS Libraries You Should Check Out

Animate.css 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.

Water.css

14 CSS Libraries You Should Check Out

Water.css 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.

Spectrum CSS

14 CSS Libraries You Should Check Out

Spectrum CSS 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.

Box-shadows.css

14 CSS Libraries You Should Check Out

Box-shadows.css 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.

sButtons

14 CSS Libraries You Should Check Out

sButtons 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.

Hint.css

14 CSS Libraries You Should Check Out

Hint.css 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.

CSS Icons

14 CSS Libraries You Should Check Out

CSS Icons 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.

Hamburgers

14 CSS Libraries You Should Check Out

Hamburgers 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.

Balloon.css

14 CSS Libraries You Should Check Out

Balloon.css 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.

Charts.css

14 CSS Libraries You Should Check Out

Charts.css 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.

CSShake

14 CSS Libraries You Should Check Out

CSShake 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.

flag-icons

14 CSS Libraries You Should Check Out

flag-icons 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.

pattern.css

14 CSS Libraries You Should Check Out

With pattern.css you can fill the background of the page, separator, text, and image with different pattern styles using only CSS classes provided by the library.

Conclusion

CSS libraries can help you do more with less time. It saves you time and makes your website look nicer.

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.

]]>
<![CDATA[Medusa: Create A Fast and Highly Customizable E-Commerce Store]]>https://blog.shahednasser.com/medusa-create-fast-and-highly-customizable-ecommerce-store/Ghost__Post__6161d15b3eea8f060129b2fcMon, 11 Oct 2021 16:00:38 GMT

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.

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.

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.

This is where Medusa 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.

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.

Medusa's Architecture

Medusa as a full e-commerce system is split into 3 parts or 3 building blocks.

The core of Medusa is its backend. 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.

Next comes the storefront. Medusa provides 2 storefronts that you can use, one built with Next.js and another with Gatsby.js. The storefront connects to the backend and provides a slick design and a fast experience for your users.

The last building block is the admin dashboard. The admin dashboard connects to the backend and allows you to easily manage products, orders, customers, and settings.

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.

E-Commerce Features

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.

Product Variants

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.

Medusa: Create A Fast and Highly Customizable E-Commerce Store

Discounts

You can add discounts or offer free shipping based on region. You can apply the discount as a percentage or as a fixed amount.

Medusa: Create A Fast and Highly Customizable E-Commerce Store

Gift Cards

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.

Medusa: Create A Fast and Highly Customizable E-Commerce Store

Multiple Currencies

In Medusa, you can choose multiple currencies for your store and set a default one.

Medusa: Create A Fast and Highly Customizable E-Commerce Store

Multiple Regions

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.

Medusa: Create A Fast and Highly Customizable E-Commerce Store

Medusa's Strong Points

Blazingly Fast

As the frontend is decoupled from the backend, it removes the extra workload that is usually done in tightly coupled systems.

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.

Highly Customizable

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.

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.

Easy Development

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.

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.

Easy Setup and Deployment

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.

Similarly, its deployment is easy as well. Medusa's documentation already has a guide on how to deploy the backend on Heruko, and the admin dashboard on Netlify.

Medusa's Cons

No Internationalization

At the moment of writing this, Medusa does not support multiple languages. Internationalization is a very important aspect of e-commerce.

So, if your store needs to support languages other than the English language, then Medusa is not a good option.

Medusa's roadmap shows that Localization is a planned task. So, in the future, it should be available.

Lack of Community Plugins

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.

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.

Simple Storefront

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.

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.

When Should You Use Medusa

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.

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.

Medusa is also one of the very few options available to build e-commerce stores with modern technologies.

Conclusion

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.

You can get started with Medusa in minutes with their Quickstart documentation.

]]>
<![CDATA[5 Tips To Become A React Native Developer]]>https://blog.shahednasser.com/5-tips-to-become-a-react-native-developer/Ghost__Post__615c9bad3eea8f060129b2cdThu, 07 Oct 2021 13:31:24 GMT

React Native 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.

React Native developers 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.

What Is React Native?

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.

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.

Tips for Becoming a React Native Developer

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:

Learn JavaScript First

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.

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.

5 Tips To Become A React Native Developer

Understand What Makes React Native Different

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.

Familiarize Yourself with the Official Documentation

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.

Watching or reading a React Native tutorial 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.

Learning About Navigation Concepts

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.

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.

Challenge Yourself to Complete React Native Projects

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.

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.

Conclusion

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. Start your journey now!

]]>
<![CDATA[Top 9 Software Ideas for Start-Ups for The Year 2022]]>https://blog.shahednasser.com/top-9-software-ideas-for-start-ups-for-the-year-2022/Ghost__Post__615c29963eea8f060129b225Tue, 05 Oct 2021 11:24:22 GMT

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 on-demand software development companies have raised more than 200 percent of the developing cloud index's total capital and have a market value of around $2.4 trillion.

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.

Management of Rental Properties

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:

  • Rental collecting, reminders for payments, and receipts for payments.
  • For smooth payment collection, integrate online payment and e-wallet.
  • Upkeep and repair.
  • Management of complaints and feedback.
  • Management by commission.

Investor Journal

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.

Using the collected expertise stored in this program, investors may revise and examine previous investments in order to enhance their performance.

Chatbot Solution Powered by Virtual AI

Since 2014, the number of people who shop digitally has increased dramatically.

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.

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.

Collaborative Tool for Teams and Platform for Team Development

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.

The global market for team collaboration software is estimated at $27.8 billion by 2028 as per Global Newswire.

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. – Survey conducted by Flexjobs.

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.

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.

Develop a Medical Software Program

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.

By Statista, medical software is predicted to reach $4.26 billion in global sales by 2025. As can be seen, there are several changes in this field. There are many healthcare software development businesses that may assist you in developing medical software and bringing your idea to life.

Top 9 Software Ideas for Start-Ups for The Year 2022

Itinerary Maker for Trips

Although the tourist business appears to be suffering at the moment, this sector is poised for rapid expansion after the epidemic is over.

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.

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.

Solutions for Email Delivery

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.

Numerous enhancements are possible, including user interface, ease of setup, customer experience, and cost.

Password Organiser

There are 80 applications on average for every smartphone user. 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.

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.

Platform for Online Training and Coaching

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.

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.

Conclusion

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.

]]>
<![CDATA[How to Style a Video Player and Create a Custom Player]]>https://blog.shahednasser.com/how-to-style-a-video-player-and-create-a-custom-player/Ghost__Post__6156dfc23eea8f060129b071Mon, 04 Oct 2021 14:46:31 GMT

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.

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.

Using Pseudo-Element Selectors

Video elements, by default, is not visible. We need to add the controls attribute to the HTML tag to make it visible.

Default Video Element

By default, here's how a video element looks like: