<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Richard Choi</title>
    <description>The latest articles on Forem by Richard Choi (@choir241).</description>
    <link>https://forem.com/choir241</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1625250%2Fe1d9f035-1aef-41c6-a2cf-7c56dc847732.jpg</url>
      <title>Forem: Richard Choi</title>
      <link>https://forem.com/choir241</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/choir241"/>
    <language>en</language>
    <item>
      <title>React built-in hooks: useCallback</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Wed, 28 May 2025 21:32:53 +0000</pubDate>
      <link>https://forem.com/choir241/react-built-in-hooks-usecallback-4972</link>
      <guid>https://forem.com/choir241/react-built-in-hooks-usecallback-4972</guid>
      <description>&lt;p&gt;If you didn't catch my previous React built-in hooks &lt;a href="https://dev.to/choir241/react-built-in-hooks-useactionstate-39f9"&gt;blog about useActionState&lt;/a&gt;, this is a continuation of that series.&lt;/p&gt;

&lt;p&gt;Previously I was introduced to useCallback when I asked ChatGPT once to optimize my frontend code, but I never took a deeper look into it (and frankly I regret it now), so I used it everywhere I could along with useMemo (which I'll cover later in this series).&lt;/p&gt;

&lt;p&gt;While it's not inherently a signficant bad thing to have useCallback all around your code, it can clutter up the readability of your code, but it's encouraged you use it where needed.&lt;/p&gt;

&lt;p&gt;So when should you use it? useCallback is meant for expensive callback functions that are used in granular applications like drawing software, as it loads the initial function on render but does not re-render like React usually does with its functions unless the dependencies change.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/components/menu.jsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client";
import { useState, useCallback } from "react";
import axios from "axios";

export default function Menu({ setMenu, menu }) {
  const [newItem, setNewItem] = useState("");

  const handleClick = useCallback(async () =&amp;gt; {
    try {
    if(newItem){
        const response = await axios.get("http://localhost:8000/menu");
        setMenu([{name: newItem}, ...response.data]);
    }else{
        const response = await axios.get("http://localhost:8000/menu");
        setMenu(response.data);
    }

    } catch (err) {
      console.error(err);
    }
  }, [newItem]);

  function addItem() {
    setMenu([...menu, { name: newItem }]);
  }

  return (
    &amp;lt;main&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; handleClick()}&amp;gt;Click&amp;lt;/button&amp;gt;

      &amp;lt;input type="text" onChange={(e) =&amp;gt; setNewItem(e.target.value)} /&amp;gt;
      &amp;lt;button
        onClick={(e) =&amp;gt; {
          e.preventDefault();
          addItem();
        }}
      &amp;gt;
        Add Item
      &amp;lt;/button&amp;gt;

      {menu &amp;amp;&amp;amp; menu.length ? (
        menu.map((item) =&amp;gt; {
          return (
            &amp;lt;div key={item._id}&amp;gt;
              &amp;lt;section&amp;gt;{item.name}&amp;lt;/section&amp;gt;
            &amp;lt;/div&amp;gt;
          );
        })
      ) : (
        &amp;lt;&amp;gt;Something went wrong, please try again later&amp;lt;/&amp;gt;
      )}
    &amp;lt;/main&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app/page.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client"
import {useEffect, useState} from "react";
import axios from 'axios';
import Menu from "./components/menu.tsx";

export default function Home () {

const [menu, setMenu] = useState([]);
const [data, setData] = useState([]);

useEffect(()=&amp;gt;{
  async function getMenu (){
    const response = await axios.get("http://localhost:8000/menu");
    setData(response.data);
  }
  getMenu();

},[]);

  return(
    &amp;lt;main&amp;gt;
      {data.map((ele)=&amp;gt;&amp;lt;&amp;gt;{ele.price}&amp;lt;/&amp;gt;)}

      &amp;lt;Menu setMenu = {setMenu} menu = {menu}/&amp;gt;
    &amp;lt;/main&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My hope with this series is to bring underrated built-in hooks to light, as well as highlight some things you may not have known about familiar hooks.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>React built-in hooks: useActionState</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Tue, 27 May 2025 20:18:34 +0000</pubDate>
      <link>https://forem.com/choir241/react-built-in-hooks-useactionstate-39f9</link>
      <guid>https://forem.com/choir241/react-built-in-hooks-useactionstate-39f9</guid>
      <description>&lt;p&gt;This is the start of my React built-in hooks series, where I took some time to look at the React docs and have a deeper look into each respective built-in hook, even the ones I'm already very familiar with.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useActionState&lt;/code&gt; has some interesting use cases where it provides a way to store your state along with a loading transition for the action callback you pass for the form to trigger upon submission. &lt;/p&gt;

&lt;p&gt;What this means is that by using a server function to grab your form input values by their unique name attributes, you're able to tell the code to wait for the form submission action to be completed before you're able to see the updated data.&lt;/p&gt;

&lt;p&gt;Here is my demo, where you can see it in action (hehe). The code informs the user that it's currently loading until the form submission is complete. You can see this demonstration with the failed request in a delayed time to observe it in action and how quickly it runs without delay.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjm1br09a310hety8j0ml.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjm1br09a310hety8j0ml.gif" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app/page.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client"
import React, {useActionState} from "react";
import {addToCart} from "./hooks/addToCart";

export interface ICart {
  itemID: string,
  itemTitle: string,
  itemPrice: number,
  itemQuantity: number
}

export const cart: ICart[] = [];

function AddToCartForm({itemTitle, itemID, itemPrice}:{itemTitle: string, itemID: string, itemPrice: number}) {
 const [cartItem, cartAction, isPendingCart] = useActionState(addToCart, {itemTitle: "", cartID: "", itemPrice: 0, itemQuantity: 0});

  return (
      &amp;lt;form action = {cartAction}&amp;gt;
      &amp;lt;h2&amp;gt;{itemTitle} ${itemPrice}&amp;lt;/h2&amp;gt;

      &amp;lt;input type="hidden" name="itemID" value={itemID} /&amp;gt;
      &amp;lt;input type="hidden" name="itemTitle" value={itemTitle} /&amp;gt;
      &amp;lt;input type="hidden" name="itemPrice" value={itemPrice} /&amp;gt;
      &amp;lt;label&amp;gt;Add number of items to cart: &amp;lt;/label&amp;gt;&amp;lt;input type="number" name="itemQuantity"/&amp;gt;

      &amp;lt;button type="submit"&amp;gt;Add to Cart&amp;lt;/button&amp;gt;
      &amp;lt;span&amp;gt;{cartItem.message}&amp;lt;/span&amp;gt;

      {isPendingCart ? "Loading..." : &amp;lt;section&amp;gt;
        &amp;lt;h2&amp;gt;{cartItem.itemTitle}&amp;lt;/h2&amp;gt;
        &amp;lt;h4&amp;gt;{cartItem.total}&amp;lt;/h4&amp;gt;
        &amp;lt;/section&amp;gt;}
      &amp;lt;/form&amp;gt;
  );
}

export default function Home(){
  return(
    &amp;lt;main&amp;gt;
      &amp;lt;AddToCartForm itemTitle={"Hatsune Miku shirt"} itemID = {"1"} itemPrice={12.12}/&amp;gt;
    &amp;lt;/main&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app/hooks/addToCart.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use server"

export async function addToCart(prevState, queryData){
  const itemID:string = queryData.get('itemID');
  const itemTitle:string = queryData.get('itemTitle');
  const itemPrice:number = queryData.get('itemPrice');
  const itemQuantity:number = queryData.get('itemQuantity');

  const message = "Item was added to cart!"

  if (itemID &amp;amp;&amp;amp; itemTitle &amp;amp;&amp;amp; itemPrice &amp;amp;&amp;amp; itemQuantity &amp;gt; 0) {
    const total = itemPrice * itemQuantity
    return {itemID, itemTitle, itemPrice, itemQuantity, message, total};
  } else {
    // Add a fake delay to make waiting noticeable.
    await new Promise(resolve =&amp;gt; {
      setTimeout(resolve, 2000);
    });
    const total = itemPrice * itemQuantity
    const message = "Enter a valid quantity!"

    return {itemID, itemTitle, itemPrice, itemQuantity, message, total};
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My hope with this series is to bring underrated built-in hooks to light, as well as highlight some things you may not have known about familiar hooks.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>My thoughts on Pieces</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Wed, 20 Nov 2024 17:18:56 +0000</pubDate>
      <link>https://forem.com/choir241/my-thoughts-on-pieces-3cmc</link>
      <guid>https://forem.com/choir241/my-thoughts-on-pieces-3cmc</guid>
      <description>&lt;p&gt;There are a lot of AI tools to choose from in our current climate of AI. I ended up trying &lt;a href="https://pieces.app/" rel="noopener noreferrer"&gt;Pieces&lt;/a&gt; because I met some of their team members at &lt;a href="https://thatconference.com/wi/2024/" rel="noopener noreferrer"&gt;THAT conference WI&lt;/a&gt;. It was free, and I figured why not at least give it a try. To this day, I still use it throughout my workday; however it's far from perfect, and I want to talk about it all: the good, the bad, and my overall thoughts.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Pieces
&lt;/h2&gt;

&lt;p&gt;So what even is Pieces? To oversimplify it, Pieces is a Copilot AI tool. But it's more than that. It also lets you choose which LLM model you want to use. So if you're more particular to Claude, you can use it, or if you prefer ChatGPT, you can use that instead.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcx47ybv93f6co4ipkbp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhcx47ybv93f6co4ipkbp.png" alt="Pieces Manage Copilot Runtime popup menu" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Offline features
&lt;/h3&gt;

&lt;p&gt;You can also use it offline, giving you access to the many features Pieces currently provides without worrying about the quality of your internet connection.&lt;/p&gt;

&lt;p&gt;Because it goes offline, you also never have to worry about any of the information you upload to the prompts being exposed because it's all on the device, unlike using ChatGPT on its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Snippets
&lt;/h3&gt;

&lt;p&gt;If you want to save code snippets, you can do so by using the browser of your choice and the &lt;a href="https://docs.pieces.app/#web-browsers" rel="noopener noreferrer"&gt;Pieces browser extension&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxef4f8lds1j89wtpm9k9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxef4f8lds1j89wtpm9k9.png" alt="screenshot of google chrome pieces extension on side of pieces for developers website" width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are also &lt;a href="https://docs.pieces.app/#ides-and-editors" rel="noopener noreferrer"&gt;code editor extensions&lt;/a&gt; like the Visual Code extension to give you access to Pieces while you're coding. This allows users to continue coding while reducing the need to keep going back and forth between coding and ChatGPT, allowing the user to stay focused on their code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqs4itvwhpxwv8kt5bce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqs4itvwhpxwv8kt5bce.png" alt="screenshot of visual code editor pieces extension on side of typescript code" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-term memory
&lt;/h3&gt;

&lt;p&gt;Pieces also has a feature called &lt;a href="https://docs.pieces.app/product-highlights-and-benefits/live-context" rel="noopener noreferrer"&gt;Long Term Memory&lt;/a&gt; as of writing this blog, where you are able to upload files and folders to it. The files and folders provide the AI LLM model with the proper context to give you a more accurate answer for your prompts by using the content you provided.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45c43q38bhqbwm9al36y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45c43q38bhqbwm9al36y.png" alt="screenshot of pieces desktop pop-up of long term memory file upload" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What could Pieces improve on?
&lt;/h2&gt;

&lt;p&gt;No product is perfect, and this also applies to Pieces. As of writing this blog, there are a few things I think Pieces as a product could be improved upon. For context, I'm using a Windows OS device. &lt;/p&gt;

&lt;h3&gt;
  
  
  Pieces OS
&lt;/h3&gt;

&lt;p&gt;Firstly, it's inconvenient having to click on the prompt boxes every time I update the Pieces OS, especially since I have to open up the dropdown menu for both of them if I want to make my selection of network. I should only have to do these prompts once when I download Pieces initially.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bpflg8vuzdbhvex8n9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bpflg8vuzdbhvex8n9t.png" alt="screenshot of pieces desktop in background with windows security pop-up window for Pieces OS network access on top" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5innzwh0widdc6mdi3qz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5innzwh0widdc6mdi3qz.png" alt="screenshot of pieces desktop in background with windows security pop-up window for Pieces Qdrant Server network access on top" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Considering that Pieces OS needs to be running in the background for any Pieces features to work properly, I wish there was a hot key to run Pieces OS and disable it as well. I'm not sure if this is actually possible, but it would be very nice to have.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-Term Memory
&lt;/h3&gt;

&lt;p&gt;When I want to use the Long Term Memory feature and upload a file or folder to provide context, the pop-up window gets hidden from view and I have to click in the taskbar to continue. This seems to be an issue specifically for Windows users, and this also has been occurring for the Pieces code editor extensions as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2d0f0m1xbd4y5k6h95b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2d0f0m1xbd4y5k6h95b.gif" alt="GIF demonstrating issue of clicking on select files for Pieces Long Term memory" width="360" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bas1bfqq0vujibxz1pe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bas1bfqq0vujibxz1pe.gif" alt="GIF demonstrating issue of clicking on select folders for Pieces Long Term memory" width="360" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Snippets
&lt;/h3&gt;

&lt;p&gt;I'll be very honest with you: I don't use the saved snippets feature for Pieces. The biggest reason is that I really like the convenience that &lt;code&gt;Ctrl + C&lt;/code&gt; and &lt;code&gt;Ctrl + V&lt;/code&gt; provide. There's less friction to copy and paste a code snippet versus opening up Pieces OS, downloading the Pieces browser extension, clicking on the copy code snippet button, and then pasting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copilot
&lt;/h2&gt;

&lt;p&gt;The quality of Pieces Copilot is based on the LLM models you select - Claude, ChatGPT, Gemini, Bison, etc. So I would recommend experimenting around with them since Pieces provides the platform to do so, especially since Pieces is free at the moment. &lt;/p&gt;

&lt;p&gt;However, I should add that a lot of the LLM models have been configured to focus primarily on technology-based prompts, so if you're looking to use it for your everyday use, this product may not be for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qf9zl885epgkc0wi9d1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qf9zl885epgkc0wi9d1.png" alt="Screenshot of Pieces prompts not being able to generate response for non-technical prompts" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As of writing this article, if you want to edit, delete, or use a prompt as context, you need to scroll all the way to the top in order to do so. This feels like a lot of scrolling as a user, and it discourages me from using any of those features in the first place. Thankfully you're able to copy the prompts by right-clicking on them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9alj30b8m5wwm15mwp1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9alj30b8m5wwm15mwp1.gif" alt="GIF demonstrating scrolling up through a long prompt in Pieces to access edit, delete, and use as context options for the prompt" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Would I recommend the product?
&lt;/h2&gt;

&lt;p&gt;Honestly, it's hard to say. With the recent hype of AI and the rampant increase of AI tools, it can be hard for me to recommend AI tools. Pieces still have ways to go as a product, but there is definitely potential there.&lt;/p&gt;

&lt;p&gt;I would take everything you read in this article into consideration in order to determine if Pieces is the right product for you. If you would like to go deeper into what Pieces offers, I would take a look at their &lt;a href="https://docs.pieces.app/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Reach out to me here:&lt;br&gt;
&lt;a href="https://x.com/choir241" rel="noopener noreferrer"&gt;My Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://linkedin.com/in/richard-choir" rel="noopener noreferrer"&gt;My Linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bsky.app/profile/choir241.bsky.social" rel="noopener noreferrer"&gt;My Bluesky&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.instagram.com/225kh_drw/" rel="noopener noreferrer"&gt;My Instagram&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>pieces</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Zero to Hero: Building a Full-Stack App with PropelAuth, Vite, Typescript, Express, and MongoDB</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Mon, 18 Nov 2024 18:41:49 +0000</pubDate>
      <link>https://forem.com/choir241/zero-to-hero-building-a-full-stack-app-with-propelauth-vite-typescript-express-and-mongodb-234d</link>
      <guid>https://forem.com/choir241/zero-to-hero-building-a-full-stack-app-with-propelauth-vite-typescript-express-and-mongodb-234d</guid>
      <description>&lt;p&gt;Have you ever built your Javascript full-stack applications and wanted to integrate seamless and secure authentication without setting up all the backend for the authentication logic? We’re going to build a full-stack application that does this using &lt;a href="https://www.propelauth.com/" rel="noopener noreferrer"&gt;Propel Auth&lt;/a&gt;, a team-based authentication platform for B2B SaaS applications, with Vite as the framework, Typescript as the frontend, Express as the backend, and MongoDB as the database to store our data.&lt;/p&gt;

&lt;p&gt;So why Propel Auth? Not only does Propel Auth allow a variety of authentication options like 2FA or SAML, it also allows you to manage your relationships with the created users, improving the overall user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Vite
&lt;/h2&gt;

&lt;p&gt;We will need to set up the foundations of our application first, so use the command below and follow the wizard prompts for React and Typescript. Feel free to customize the project name, but for the sake of this example, we are going to call this project VTuberHub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;vite&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to install the packages to run your &lt;a href="https://vite.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; app, and test it locally to make sure you set it up correctly. Now that we have our framework set up, we can start working on setting up our Database!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup MongoDB
&lt;/h2&gt;

&lt;p&gt;If you don’t have an account, you can sign up for a free account at the &lt;a href="https://www.mongodb.com" rel="noopener noreferrer"&gt;MongoDB site&lt;/a&gt;. Create an organization and customize the name for your purposes, but we will be calling it My-Project for this example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hqqvmgkexnbrl9bocbq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hqqvmgkexnbrl9bocbq.png" alt="MongoDB Name Your Project with My-project in the input screenshot" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do the same for your project and its name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0omm5q6yg6ayx2lspng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0omm5q6yg6ayx2lspng.png" alt="MongoDB prices list and name of cluster screenshot" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deploy your new cluster, where your Database will be located. For the sake of this example, we will be calling it Vtubers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kso84psotnzoxt4zwwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5kso84psotnzoxt4zwwd.png" alt="PropelAuth dashboard my project as the name of the project screenshot" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are almost finished with setting up our database! Make sure to configure who has access to the Database under the Database Access sidebar navigation and set up a password for the user, we will need this for later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Propel Auth
&lt;/h2&gt;

&lt;p&gt;If you haven't already, make sure to create a &lt;a href="https://auth.propelauth.com/en/login" rel="noopener noreferrer"&gt;PropelAuth account&lt;/a&gt;. You'll want to create your project and give it a name. For this article, we'll be calling it my project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1365vp0h7blmplek59gs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1365vp0h7blmplek59gs.png" alt="PropelAuth frontend integration with http://localhost:5173 in Application URL input screenshot" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll need to install propel auth to our project by using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @propelauth/react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to Frontend integration and enter &lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt; under the Application URL input box. This way, we can tell Propel Auth where our Vite application is running locally, allowing requests like POST or GET from our project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnarh47c8k8ulz7e2i93.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnarh47c8k8ulz7e2i93.png" alt="Propel Auth frontend integration Application URL http://localhost:5173 int input screenshot" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll need to copy and paste your Auth URL into your &lt;code&gt;.env&lt;/code&gt; file so we can access it later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;VITE_AUTH_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://something.propelauthtest.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to set up your &lt;code&gt;main.tsx&lt;/code&gt; properly for Vite by wrapping our application in the &lt;code&gt;AuthProvider&lt;/code&gt; component so we can fetch the current user's authentication information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StrictMode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRoot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.tsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AuthProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@propelauth/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StrictMode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthProvider&lt;/span&gt; &lt;span class="nx"&gt;authUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VITE_AUTH_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/AuthProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/StrictMode&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we're all setup with our frontend, lets build a simple UI toggle depending on if the user is signed in or not!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;withAuthInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useRedirectFunctions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;useLogoutFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;WithAuthInfoProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@propelauth/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;YourApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withAuthInfo&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WithAuthInfoProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logoutFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLogoutFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;redirectToLoginPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirectToSignupPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirectToAccountPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRedirectFunctions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;logged&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;redirectToAccountPage&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;logoutFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Logout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;logged&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;redirectToLoginPage&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;redirectToSignupPage&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Signup&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;YourApp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks good, now let's start working on our backend so we can add data to our database from our frontend!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Backend
&lt;/h2&gt;

&lt;p&gt;We’ll need to now set up our backend so we can handle our frontend requests to send data to our Database. Make sure to create a separate folder for your backend before initializing the express backend using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-y&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will need to install certain dependencies for our example application needs. Outside of Express and MongoDB, we will be using the dotenv package to prevent exposing our environment variables, and the cors package to enable our users to access our backend API requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mongodb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we install all our packages, we will need to import them into our backend code logic using the &lt;code&gt;require()&lt;/code&gt; function. Make sure to use the cors function to enable its use by frontend users, the critical function &lt;code&gt;express.json()&lt;/code&gt; for JSON data handling, and the express server hosting for the backend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Start the server&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running on port 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to set up the connection from our backend to the MongoDB database we just created. Remember the password I mentioned in the MongoDB set up section?&lt;/p&gt;

&lt;p&gt;We need it here for the MongoDB connection URL, which you can find in &lt;strong&gt;Clusters&lt;/strong&gt; → &lt;strong&gt;Connect&lt;/strong&gt; → &lt;strong&gt;Drivers&lt;/strong&gt; → Copy the MongoDB connection string and replace the password with the one you created in the MongoDB setup section. This is the connection URL you will be using in your &lt;code&gt;.env&lt;/code&gt; file to protect exposing it, and for the sake of this example, we will be calling it &lt;code&gt;MONGO_URL&lt;/code&gt;. Make sure your &lt;code&gt;.env&lt;/code&gt; file is in the same folder as your backend files so they can grab the &lt;code&gt;MONGO_URL&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;Connect your MongoDB client with the backend and make sure your backend is properly connecting to MongoDB before proceeding forward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ServerApiVersion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mongodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MONGO_URL&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MongoClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mongoUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;serverApi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ServerApiVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;deprecationErrors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Connect the client to the server (optional starting in v4.7)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Send a ping to confirm a successful connection&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Pinged your deployment. You successfully connected to MongoDB!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error connecting to server, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now for our final step, we gotta let our backend accept CRUD requests so we can create documents in our Database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myDB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myColl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/createVtuber&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;myColl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="s2"&gt;`A document was inserted with the _id: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insertedId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`error sending request, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;Time to finish up our Frontend, we still need to make the actual request to our backend and send our data! We’re going to install the Axios package to handle our API requests from the frontend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can create a function to make the POST request for our button!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addDB&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
 &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/createVtuber&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hatsune miku&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;YourApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withAuthInfo&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WithAuthInfoProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logoutFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLogoutFunction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;redirectToLoginPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirectToSignupPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirectToAccountPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRedirectFunctions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;logged&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;redirectToAccountPage&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;logoutFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Logout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;addDB&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Create&lt;/span&gt; &lt;span class="nx"&gt;Vtuber&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;logged&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;redirectToLoginPage&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;redirectToSignupPage&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Signup&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, our data wouldn’t be statically hard-coded like this, we would use state management to manage our data.&lt;/p&gt;

&lt;p&gt;But we don’t want just anyone using our backend, right? So let’s make it so only authorized users are able to access our backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding authorized users
&lt;/h2&gt;

&lt;p&gt;Going back to our backend folder, we’re going to install Propel Auth for express.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;propelauth/express&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to grab your Propel Auth URL and API key, which you can find under &lt;strong&gt;Backend Integration&lt;/strong&gt; in our Propel Auth project dashboard. We will be storing these values in our backend &lt;code&gt;.env&lt;/code&gt; file as well, which for the sake of this example will be called &lt;code&gt;AUTH_URL&lt;/code&gt; and &lt;code&gt;SECRET_KEY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We’ll need to import &lt;code&gt;initAuth&lt;/code&gt; to initialize the authentication services in our backend and add our &lt;code&gt;AUTH_URL&lt;/code&gt; and &lt;code&gt;SECRET_KEY&lt;/code&gt; variables into the &lt;code&gt;initAuth&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@propelauth/express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;requireUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;authUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AUTH_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/createUser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requireUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;myColl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`A document was inserted with the _id: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;insertedId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`error sending request, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our frontend, we just have to add the access token to our headers when we make our POST request, and if we’re signed in, we will have the proper authorization to make the request to our backend server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addDB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/createUser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hatsune miku&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So our frontend should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;addDB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3000/createUser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hatsune miku&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use Tailwind/CSS to make the app look pretty, and voila! Our example full-stack application is finished, and we know how to integrate Propel Auth with Express, Vite, TypeScript, and MongoDB. For a deeper dive into Propel Auth and what it provides, look into their &lt;a href="https://docs.propelauth.com/overview/authentication/api-keys" rel="noopener noreferrer"&gt;API Key Authentication&lt;/a&gt;, or how they &lt;a href="https://docs.propelauth.com/overview/authorization/managing-roles-permissions" rel="noopener noreferrer"&gt;manage role permission&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>mongodb</category>
      <category>express</category>
      <category>vite</category>
    </item>
    <item>
      <title>Low-Level Documentation</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Tue, 05 Nov 2024 13:33:11 +0000</pubDate>
      <link>https://forem.com/choir241/low-level-documentation-41k9</link>
      <guid>https://forem.com/choir241/low-level-documentation-41k9</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Frontend: TypeScript&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need to decide what frontend technology stack we want to use alongside Next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The technology stack needs to be compatible with Next&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The technology stack needs to offer features that will make development more smooth&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TypeScript will be used to check the types of all possible data types within the code without having to write any additional code for conditional statements to check for data types.  Also, Typescript provides an easier debugging experience, as it always catches errors in the code without having to run it.&lt;/p&gt;

&lt;p&gt;TypeScript is a bit more complex when going in deeper, but on the surface level, it is quite easy to pick up if you already know React; if you know HTML and JS already, you are halfway there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detailed Design:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The intent is to use TypeScript for components and elements of the code that would benefit greatly from the type-checking nature of TypeScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;countContext&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;useStore&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Zustand&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../api/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/Values.tsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mumei&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nanshi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mumei@email.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;})}&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Values&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mumei&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nanshi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mumei@email.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;})}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Test and Values components have identical arguments passed through them to demonstrate the similarities and differences between React and TypeScript components.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Component
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  TypeScript Component
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Test component here demonstrates what it would look like to use a component in React, and the Values component demonstrates what it would look like to use the same component in TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/file/9E18DvAwp3ujhDiMjEkD5T/Typescript-Design?type=whiteboard&amp;amp;node-id=0-1&amp;amp;t=3in7q2Oxl6Xt0AnE-0" rel="noopener noreferrer"&gt;See Figma Example of using Typescript in the Gridiron Survivor application&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, a simple design has been created to demonstrate a use-case for TypeScript, where the type-checking in TypeScript is used to ensure that all the data values are the appropriate data types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TypeScript detects errors in code without running it, otherwise known as static checking.  It also checks the types of any data type (obj, string, number, etc), making sure to send warnings when the wrong data type is being used or passed through.  There is also the option of printing the code output to the console to ensure that the code is working as intended.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript Official Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Module Builder: Webpack 5&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need a module builder that will handle the bundling of our JS application and allow us to configure the particular type of build.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The module builder needs to be compatible with Next.js&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The module builder needs to be able to handle the bundling of our JS application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The module builder needs to allow the configuration of the type of build&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Webpack 5 is included upon installation of Next, and it let you bundle your JavaScript applications, supporting both ESM and CommonJS.  They also allow the configuration of the type of build for your application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detailed Design:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Upon creating a new Next application using the create-next-app@latest command, the following default configurations for Webpack 5 will be shown in the tsconfig.json file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compilerOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;target&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dom.iterable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;esnext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allowJs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;skipLibCheck&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strict&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;noEmit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;esModuleInterop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;esnext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moduleResolution&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resolveJsonModule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isolatedModules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;preserve&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;incremental&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;include&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next-env.d.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/*.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/*.tsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.next/types/**/*.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jest.config.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;exclude&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node_modules&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What each property means for Webpack 5:&lt;/p&gt;

&lt;p&gt;Next Create App Features&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Target:&lt;/strong&gt; tells runtime code to generate in a specific environment&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lib:&lt;/strong&gt; defines the libraries that will be included in the compilation process&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AllowJs:&lt;/strong&gt; enables the compilation of JavaScript files&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SkipLibCheck:&lt;/strong&gt; skips the type checking of declaration files (files with .d.ts extensions)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strict:&lt;/strong&gt; enables strict type-checking options mode for TypeScript&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noemit:&lt;/strong&gt; prevents TypeScript from emitting output files&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Esmoduleinterop:&lt;/strong&gt; enables the compatibility between ESmodules and commonJS&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Module:&lt;/strong&gt; specifies the module code generation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Module resolution:&lt;/strong&gt; determines how Webpack will resolve modules&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ResolveJsonModule:&lt;/strong&gt; allows TypeScript to import JSON modules directly&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Isolated Modules:&lt;/strong&gt; ensures each file is treated as a separate module. This can improve build performance&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSX:&lt;/strong&gt; specifies JSX factory function to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incremental:&lt;/strong&gt; enables incremental compilation, allowing TypeScript to cache compilation results and speed up subsequent builds&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plugins&lt;/strong&gt;: an array of TypeScript plugins&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paths:&lt;/strong&gt; defines path mapping for module imports&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Include&lt;/strong&gt;: specifies files to include in TypeScript compilation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exclude&lt;/strong&gt;: specifies files to exclude in TypeScript compilation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/messages/webpack5" rel="noopener noreferrer"&gt;Next official documentation on Webpack 5 Adoption&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/app/api-reference/next-config-js/webpack" rel="noopener noreferrer"&gt;Next official documentation on configuring your custom webpack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;Webpack official website&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Routing: Next App Routing&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need a way to create different pages so the user can navigate through the application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Problem Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The feature needs to be able to allow the creation of new pages, where each new page will represent a new route domain within the application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next Routing moves to different pages of the application while remaining a single-page application.  It is also automatically available upon installing Next, and there is a simple setup available upon creating a new Next application using the create-next-app@latest command.&lt;/p&gt;

&lt;p&gt;The goal is to assign different pages to different elements of the application.  Not only to be able to organize the code into separate pages but also to find a way to host an API and/or HTTP requests for the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detailed Design:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Without requiring a separate application to host the backend and receive the HTML requests that will be made, the API Routes will allow us to define our API routes in our application.  Not only will this be more convenient, but this will also save time and make collaboration between the backend team and the frontend/functional team more smooth and streamlined.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/file/6l45QWUG6mVpX1SOs8lJyM/Routing-Detailed-Design?type=whiteboard&amp;amp;node-id=1-104&amp;amp;t=J5p2YNC4Gr22yafw-0" rel="noopener noreferrer"&gt;Figma Design Example of using Next Routing in the Gridiron Survivor Application&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is to have a separate page for the main component, ie. a page for authentication called pages/authentication, a page for the user profile called pages/userProfile, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App Router Setup:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/choir27/Next-App-Routing" rel="noopener noreferrer"&gt;Github Repository Example of using Next App Routing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page Router Setup:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/choir27/Next-Page-Routing" rel="noopener noreferrer"&gt;Github Repository Example of using Next Page Routing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the API routes, print to the console to make sure that each API route is being registered properly and it was set up properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/docs/pages/building-your-application/routing" rel="noopener noreferrer"&gt;Next official documentation on building your application routing&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;State Management: Context API and Zustand&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Authors: Richard Choi&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We need a way to manage all of our states while avoiding the pitfall of prop drilling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need a way to re-render our entire application upon successful authentication to prepare the authenticated content post-authentication&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Problem Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It needs to be able to not only store the state and the state values but also make them available on every level of the application to prevent prop drilling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It needs to be able to cause the entire application to re-render for authentication and post-authentication&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Context API and Zustand manage your states, making them available at any level of the application.  If set up correctly, Context API can cause the entire application to re-render and make the data globally available throughout the application, while Zustand focuses more on the individual level of making the states and state values available in the application.&lt;/p&gt;

&lt;p&gt;Both solutions avoid the pitfall of using prop drilling, as they can be made available at any level of the application.  They make states more organized, giving the other team members a better understanding of each state's usage, and functionality, and it makes it easier for them to navigate through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detailed Design:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They handle state changes, mostly from input, and they also allow us to access all kinds of data from any level of the application using Zutand and Context API.&lt;/p&gt;

&lt;p&gt;Zutand: Setup state store in a separate file, and categorize each store object into the respective components, creating nested stores when/if necessary. Access the necessary store(s) from the file path including the Zutand stores, and reinitialize variables to access the necessary states/functions/values from the Zutand store objects.&lt;/p&gt;

&lt;p&gt;Context: Setup context middleware file/folder, accessing the created context to wrap the context provider around the components that need to access the respective data/states.  Implement the states/values/functions using the value property, and access them from your controlled child components using the useContext hook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/file/U2iFdSq8BkBfBs0Bm5oyXd/State-Management-Detailed-Design?type=whiteboard&amp;amp;node-id=0-1&amp;amp;t=5t5u3cnQbod40HV4-0" rel="noopener noreferrer"&gt;Figma Design Example of using Zustand States and local States in the Gridiron Survivor Application&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next App Zustand Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/choir27/Next-Zustand-Setup" rel="noopener noreferrer"&gt;Github repository example of using Zustand in a Next application&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Upon creating a state and path for them, we intend to print to the console to test if the states work properly by printing the values that correspond to the state.  We will know when these features stop working when the console prints out undefined/null/falsy values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Launch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To launch these features, one must change/update the state value that corresponds to the state manager.  To monitor the state managers, the React Developer Tools are a good way to determine what is being re-rendered upon a state update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.pmnd.rs/zustand/getting-started/introduction" rel="noopener noreferrer"&gt;Zustand Official Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/reference/react/useContext" rel="noopener noreferrer"&gt;Documentation about the React hook useContext&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://react.dev/learn/passing-data-deeply-with-context" rel="noopener noreferrer"&gt;React official documentation on Passing Data Deeply with Context&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Caching: Session Storage and Local State&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Authors: Richard Choi&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need a way to persist our data so that when the user leaves the application tab or refreshes the screen, the data will remain upon returning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Problem Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This feature needs to be able to persist data regardless of refresh or exiting the tab&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This feature also needs to be able to be timed out after a certain amount of time to ensure the data does not persist forever&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Session storage only maintains the session/data of the current tab/page. A new one is created every time a new tab is created.  Local state only maintains the data when exiting the tab, not the window, and does not maintain the data upon refreshing the screen.&lt;/p&gt;

&lt;p&gt;They help us maintain the data on screen/for code despite other circumstances.  They also provide convenience to the user, so if they input something, but they accidentally exit out of the program, their “place” is “saved” thanks to cache storage.  It gives a kind of safety net for other team members when testing the application, preventing them from “losing” their “saved data” from an accidental click/exit.  Context API can be used to re-render the entire application to implement localization and to ensure content is rendered upon successful authentication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detailed Design:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/file/TijuGcv2Ea5spYUJ3MEHjY/Cache-Detailed-Design?type=whiteboard&amp;amp;node-id=0-1&amp;amp;t=Yezb2KCKQ97O2FpU-0" rel="noopener noreferrer"&gt;Figma Design Example of using Cache in the Gridiron Survivor Project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have objects to represent all the session storage/local storage we plan to use, using unique names for each object and key name, and store them all in one file called cache.  Export those objects, and import them into components that need to access those cache data to implement more clean and organized code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Print to the console for session storage to make sure that the values are being saved properly, or you can also use the inspect tool, and under the application tab under storage, you can visibly see the different properties you have to check the values of them all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage" rel="noopener noreferrer"&gt;MDN documentation about session storag&lt;/a&gt;e&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Consistency is King, and here's why.</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Mon, 04 Nov 2024 14:00:25 +0000</pubDate>
      <link>https://forem.com/choir241/consistency-is-king-and-heres-why-5ean</link>
      <guid>https://forem.com/choir241/consistency-is-king-and-heres-why-5ean</guid>
      <description>&lt;p&gt;Have you ever started something but never finished it, like learning a new language, a regimented workout routine, or a coding application? I have. Frankly, it was too many times to count, and I became tired of it.&lt;/p&gt;

&lt;p&gt;So what did I do? I did what any good developer does: break down the problem into digestible chunks and tackle them one by one. So I bought a journal and wrote down those chunks into actionable items I wanted to accomplish for that day, like stretching, building a component, or writing the introduction of a blog 😉, and I would work on those actions daily to build towards accomplishing the overall goal.&lt;/p&gt;

&lt;p&gt;What you do doesn't need to accomplish a lot nor does it need to be every day. They can be small items like walking outside for 5 minutes every day or practicing piano for 10 minutes every Monday. It may seem like these small items won't achieve anything on their own, but that was never the goal.&lt;/p&gt;

&lt;p&gt;We want to build up a good habit by making the process as frictionless as possible to introduce a new activity into your daily schedule, and then iterate on it as we continue doing it daily. For instance, once we are consistently drawing for 10 minutes every weekday, we increase the period we're drawing for from 10 minutes to 20 minutes. Then when we're comfortable drawing for 20 minutes, we increase it to 30 minutes, and so on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does this even work?
&lt;/h2&gt;

&lt;p&gt;You may be reading this and thinking: does this method truly work? Well, dear reader, I have a real-life example that perfectly showcases this approach in action, all starting with me doing small bit-sized daily tasks, and then eventually having them grow into fully-fledged habits and transforming myself to be highly adept and skilled at said activity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawing
&lt;/h2&gt;

&lt;p&gt;I always wanted to draw ever since I watched Avatar the Last Airbender, but I didn't know how. It seemed intimidating at first to approach, with all the complicated lines and details. But I was determined. There were so many cool things I wanted to be able to eventually create on a piece of paper on my own, so I started small.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Beginnings
&lt;/h3&gt;

&lt;p&gt;Pokemon was my main source of learning from the beginning, and I was struggling. I tried to trace to make the start easier for me to transition into free-form drawing, but it was a lot of hard and consistent work. Eventually, I was able to get to a point where I had drawn enough Pokemon daily and I got my drawings looking aesthetically good.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fugbjpp5gubngy4jmdosy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fugbjpp5gubngy4jmdosy.jpg" alt="Eevee and Mew drawing" width="612" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Experimenting and familiarizing
&lt;/h3&gt;

&lt;p&gt;So I kept going, pushing myself to iterate on what I had already accomplished. I started drawing anime and cartoon characters, familiarizing myself with the general anatomy of humans and how to translate it into paper. I also started experimenting around with ink outlines and color. I wasn't at the point where I could call myself an artist, but I was slowly moving the needle one small step at a time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcxx6nzlyhaf3a485vwo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftcxx6nzlyhaf3a485vwo.jpg" alt="Killua drawing" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Seeing progress
&lt;/h3&gt;

&lt;p&gt;Every day I would draw, and bit by bit I would see progress. I would start being able to identify specific parts of my drawings that could be better or specific parts of my drawings that I did well on. The difference between my current drawings from my Pokemon drawings was becoming bigger and bigger, and I was able to visibly see the progress I was making as an artist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9dn0ttidxqr11cba92k.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm9dn0ttidxqr11cba92k.jpg" alt="benienma drawing" width="720" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Expanding my possibilities
&lt;/h3&gt;

&lt;p&gt;I could have stopped here, but I wanted to keep improving and keep experimenting around. I wanted to see what else I could accomplish. So I started shading, and honestly, my shading at the start had a lot to be desired. Looking back at it now, I sort of cringe at the quality I had produced. But this feeling of cringe was also a positive feeling because it showed that at the time I was able to recognize what my past self needed to work on, establishing the evolution I had undergone since I started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gta8io6h2bwlzd5au99.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gta8io6h2bwlzd5au99.jpg" alt="medusa drawing" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning from failure
&lt;/h3&gt;

&lt;p&gt;I continued to push myself into projects that seemed too intimidating or larger than what I felt I could do. There were numerous amounts of failures, drawings that took hours only to turn out badly or to be thrown away. But from those failures, I was able to discover what not to do for future drawings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wcrr9csmkx5p4o77k8p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wcrr9csmkx5p4o77k8p.jpg" alt="wendy marvell drawing" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Current Me
&lt;/h3&gt;

&lt;p&gt;Stretching myself to the upper limits of my art skills, I started moving towards drawings that would take multiple days to finish. I was transitioning from finishing a drawing every day to working on one drawing every day. They were much bigger projects, taking more energy and more care into each of the details, but seeing the end results of the projects and the progress I was making was worth it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs75bng53zb1wsl8zomvf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs75bng53zb1wsl8zomvf.jpg" alt="Su-metal drawing" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what now?
&lt;/h2&gt;

&lt;p&gt;Take it upon yourself to find that one activity you have always wanted to do, like finish a coding project, or working out every day, and break them down into smaller, more digestible actions. &lt;/p&gt;

&lt;p&gt;So let's take our coding project example, if we assume it's a simple full-stack web application, we can break this down into the following: frontend, backend, and hosting. But we can break this down even further, where the frontend can be separated into the following categories: testing, components, design, pages, error boundary, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqykfx86obiye3bch4i8t.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqykfx86obiye3bch4i8t.gif" alt="Break it down dance GIF" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lets break this down even more, where we separate it into the pages we want to implement: home, login, signup, account, cart, shopping hub, etc. Then one more time for good measure with the login: labels, text and password inputs, login button, login function, and login data state management.&lt;/p&gt;

&lt;p&gt;Now we have it where we're just building the code for one login button instead of a whole frontend. We have an actionable step and a specific direction we can go towards, and while it's a slow journey to our destination, it's much more manageable and flexible. After all, slow and steady wins the race.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ze9mr03y747k0khm0xm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ze9mr03y747k0khm0xm.gif" alt="Dog riding turtle GIF" width="244" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See me being consistent in the following social platforms:&lt;br&gt;
&lt;a href="https://x.com/choir241" rel="noopener noreferrer"&gt;My Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://linkedin.com/in/richard-choir" rel="noopener noreferrer"&gt;My Linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://bsky.app/profile/choir241.bsky.social" rel="noopener noreferrer"&gt;My Bluesky&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.instagram.com/225kh_drw/" rel="noopener noreferrer"&gt;My Instagram&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softskills</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>My journey</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Wed, 04 Sep 2024 17:14:21 +0000</pubDate>
      <link>https://forem.com/choir241/my-journey-5eb3</link>
      <guid>https://forem.com/choir241/my-journey-5eb3</guid>
      <description>&lt;p&gt;What does a journey look like for you? For me, it has been an ongoing journey that started 2+ years ago.  Every journey needs a good beginning, and mine is quite literally the opposite of what you would call a "good" beginning.  I was stagnant, listless, bored, and empty: words that could easily describe a long wait at the DMV.  I only chose my major out of necessity, not out of desire, passion, or ambition.  My job selection was no different, randomly selecting job applications and going through the daily motions. The only passions I had to cling to were my love for drawing, watching anime, reading manga, and listening to music.&lt;/p&gt;

&lt;p&gt;It seemed like this would be how the rest of my life panned out, but there was no self-realization regarding this. Not yet, anyway. Turns out, all I needed was a chance to self-reflect and analyze my life choices, and Co-Vid was my golden opportunity. I had finally escaped, and I felt free to re-examine myself and started finding ways to challenge my current career path. I realized I felt unsatisfied and frustrated at my current state, and I needed to take action to change this. So I took a risk, a big one: I quit my job to search for part-time jobs. It was time to start taking control of my life, and I had to ask myself: what career field do I want to pursue? I had always been interested in computers and decided to give that an opportunity. My initial thought process was to apply for an online college to get my CS Bachelor's degree. However, I quickly realized the price was not worth it for me, and I dropped out as fast as I could.&lt;/p&gt;

&lt;p&gt;I moved on to the self-taught path, where I found myself trapped in what is famously known as "tutorial hell" among developers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flprkl29r1tbx800kcd98.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flprkl29r1tbx800kcd98.jpeg" alt="Bender the silver robot from Futurama TV series looking upwards towards the red robot devil with horns, a tail, and a pitch fork and he is on fire" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From tutorial to tutorial, I jumped and leaped and tripped and dropped. Nothing was sticking, I felt overwhelmed and lost, and I had no idea where the start line was. That was until I discovered 100 Devs. At first, I was suspicious. A 100% free training agency that had nothing but good reviews? It seemed too good to be true. It had to be a scam, this couldn't be true, could it?&lt;/p&gt;

&lt;h2&gt;
  
  
  100Devs
&lt;/h2&gt;

&lt;p&gt;Would you be surprised if I told you 100Devs' primary focus was not to teach coding, but to help people in the community get their first job in the tech field? This is because the current organizer of 100Devs Leon Noel believes that coding is a skill that anyone can learn on their own, either through tutorials, documentation, or free online resources; however 100Devs provides something those resources don't, and that is a community.&lt;/p&gt;

&lt;p&gt;A sense of community is so much stronger than you might imagine. It gives you the strength to move forward and never give up, knowing there are many others besides you taking the same journey you are or have taken the same journey before. The emotional support helps lift you, as you return the favor to those who may be struggling as well. Having many experienced members be a part of this community as well also provided a great platform for technical help whenever you were struggling on that front.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.wikia.nocookie.net%2Flotr%2Fimages%2Fd%2Fdf%2FFellowship1.jpg%2Frevision%2Flatest%3Fcb%3D20210723041619" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.wikia.nocookie.net%2Flotr%2Fimages%2Fd%2Fdf%2FFellowship1.jpg%2Frevision%2Flatest%3Fcb%3D20210723041619" alt="From right to left, in the back is Aragorn, Gandalf the Gray, Legalos, and Boromir, and in the front are Samwise, Frodo, Mary, Pippin, and Gimili" width="1926" height="797"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It was a great starting point for me. 100 Devs gave me a sense of focus and it set a solid foundation for my engineering career. Giving the support and resources to ease my way into the "seemingly intimidating" nature of coding, while providing an interconnecting pathway from multiple coding languages, tools, and libraries, 100 Devs was the perfect start of my tech journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Non-Profits, Meetups, Oh My!
&lt;/h2&gt;

&lt;p&gt;After leaving 100 Devs, I was a bit unsure of what direction to take next. There are so many libraries, languages, and tools online to learn. Since I already set the base foundations of my coding knowledge, I was able to find the next steps of my journey much faster compared to when I started it. I slowly added more tasks to my daily schedule to prevent myself from burning myself out, like learning React, re-implementing my old project with React, and optimizing my React code. I also started planning for the next day with what I wanted to accomplish and changed how I planned out my day according to what I accomplished in the past.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fa.storyblok.com%2Ff%2F178900%2F960x540%2F879a311489%2Fmahjong-soul-kan.jpg%2Fm%2Ffilters%3Aquality%2895%29format%28webp%29" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fa.storyblok.com%2Ff%2F178900%2F960x540%2F879a311489%2Fmahjong-soul-kan.jpg%2Fm%2Ffilters%3Aquality%2895%29format%28webp%29" alt="Anime girl with cat ears with bells as pigtail decorations and wearing a traditional japanese shaman dress for females with a salmon topp and a light purple skirt" width="960" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once I settled into a consistent schedule, I started to seek out meeting new people in the tech career field. I came across New York Code and Coffee, a meetup group that is organized bi-weekly where people from the tech field make new friends and exchange conversations. I reached out to multiple people online to not only become more active in the tech online community but to also meet new people and potentially make new online friends!  I also started seeking developer experience even if it was unpaid experience, and I came across Linguistics Justice League and Betheli9ht Foundation, where I volunteered as a developer for a good amount of time.&lt;/p&gt;

&lt;p&gt;I was finally at a point in my life where I could confidently say that I was happy with my career path. Although I did not have a paid job yet, I enjoyed learning new concepts, building and iterating on projects, solving problems, and experimenting with code syntax. While I was satisfied with what I had accomplished up to this point, I was still hungry to see myself improve and challenge my skills to a different height. And that's when I joined Gridiron Survivor, the perfect environment to try new things and push myself to my upper limitations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gridiron Survivor
&lt;/h2&gt;

&lt;p&gt;I didn't find Gridiron Survivor, Gridiron found me. It all started with a Twitter post, where said group truly began its origins. Shashi Lo Senior UX Engineer at Microsoft and current team leader of Gridiron Survivor, presented us with an opportunity for a product, where his friend wanted to have an application built to customize his football survivor games. Instead of creating the app on his own, Shashi suggested the idea of incorporating agile methodologies into the project to make it as similar to a corporate environment as possible while keeping it a safe environment. A few of us, me included, expressed our interest in the project and it was there where our beginnings for Gridiron Survivor began.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzmvi7j4olm1kzz4ouy7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzmvi7j4olm1kzz4ouy7.png" alt="The entire Karasuno High volleyball team on the volleyball court with volleyballs all over the ground" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The flow of the project timeline was presented, showcasing how each phase would represent the important components of the overall application's development and production. We were then tasked with going on our own to research various technology languages, libraries, and tools to determine which would serve the best for our specific application and why. We then had to present our findings to the entire team, receive feedback, finalize our research documentation, and re-presented our research.&lt;/p&gt;

&lt;p&gt;It was then that I had an epiphany thanks to Shashi pointing it out while we talked one-on-one. I realized that my time researching, organizing, and writing my documentation was fun and interesting. Noticing this, Shashi decided to pivot me to be the Documentation/Technical Writer for the application, while also allowing me to cross-function when the project needed me to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo09j1sz4dkmk1v27uasg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo09j1sz4dkmk1v27uasg.jpeg" alt="Tatsuo Kusakabe from My Neighbor's Tototoro with a pile of books while concentrating on working on a piece of paper" width="736" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I immediately started to familiarize myself with the world of technical writing, reading various articles and blogs talking about the writing conventions and thought process that goes into writing technical documentation. I then started going through existing technical documentation to receive inspiration from them and learn to differentiate good documentation from bad documentation. It was then that I came across Vincent Ge, who at the time was Appwrite's technical writer. I requested a coffee chat with him, where I was able to not only become closer to him but also receive sage advice regarding how I should approach writing technical writing and his thought process when writing technical documentation.&lt;/p&gt;

&lt;p&gt;During our conversation, I expressed my ongoing journey to find a job in the technology career field. Once it was publically posted and available by Appwrite, Vincent forwarded me the link to the Appwrite Technical Writer Intern position. Thanks to my time with Gridiron Survivor, I was able to demonstrate my work ethic, collaboration, teamwork abilities, my ability to talk in front of others about what I accomplished, and my technical documentation skills by building in public. I also was blessed with amazing people who were willing to send in strong referrals of their free will.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Next Chapter
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff38ptpfsio0n2tmvas9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff38ptpfsio0n2tmvas9w.png" alt="Spongebob Squarepants forfingers holding a piece of paper with a fancy stylized " width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't know what the future holds for me, but I know what I want to accomplish tomorrow. Day by day, I keep moving forward as I try to survive in the game we all know as life. Having accomplished a big milestone in my life by becoming a Technical Writer Intern at Appwrite, I hope to continue accomplishing great things throughout my life and be happy. And I cannot wait to see what the next chapter of my life has in store for me.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>career</category>
      <category>community</category>
    </item>
    <item>
      <title>My Personal Intro to TailwindCSS</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Wed, 04 Sep 2024 00:29:52 +0000</pubDate>
      <link>https://forem.com/choir241/my-personal-intro-to-tailwindcss-3il0</link>
      <guid>https://forem.com/choir241/my-personal-intro-to-tailwindcss-3il0</guid>
      <description>&lt;p&gt;I heard of Tailwind, but I never used it or Bootstrap for a long time, and my reasoning behind this was that I wanted to keep practicing my CSS skills while not relying on the convenience of CSS frameworks. However, I have seen Tailwind syntax across other projects when working with a group of developers, which introduced me to how tailwind syntax functions. Coming across an open role at Tailwind, I wanted to try applying, and I decided to build a small application talking about myself and my accomplishments using Tailwind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tailwind is Convenient
&lt;/h2&gt;

&lt;p&gt;Implementing my own Tailwind syntax throughout my code, the first thing that stood out to me was how clean my CSS page looked. Not having to create any of my styling or classes, it was nice to have such a clean-looking CSS page for a change. Before Tailwind, I would have to manage my CSS styling specificities, making sure certain HTML elements didn't have their styles overridden from other style rules, or ensuring particular CSS rules weren't too high in specificity. Now I no longer have to worry about managing the CSS specificities so much and can just go straight to implementing the Tailwind CSS.&lt;/p&gt;

&lt;p&gt;It was difficult creating consistent CSS class names across my multiple projects without good documentation for those CSS classes, and those projects not referencing the same CSS styling sheet. Thankfully Tailwind has both good documentation and a singular location to reference for styling. Tailwinds' consistent naming conventions for their classes reduce human error when working in a team, allowing easier communication and better teamwork. It also allows user customization for existing tailwind styles, providing flexibility for styles that may not make sense to include in certain website themes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex flex-col flex-nowrap justify-center w-4/6 mr-2 px-10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/di&lt;/span&gt;&lt;span class="err"&gt;v
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As an example of Tailwind's consistent naming pattern, let's look at the above example. For any styles that are subcategories like flex-direction or flex-wrap, Tailwind usually uses the hyphen to categorize the parent style and the child style. So when making an element's flex-direction column, Tailwind goes for flex-col to keep it short, simple, and effective. For styles that require choosing the direction for the style being implemented, Tailwind goes for the x and y-axis to represent said directions and make it easy to remember for repeated usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I observed
&lt;/h2&gt;

&lt;p&gt;When I was building my application with Tailwind, I observed as I added more Tailwind classes to an element, the more cluttered my code looked. Granted there are times when an element only needs one class, but there are also occasions where an element requires a lot of classes. As demonstrated below, there can be a lot of Tailwind classes on one element. Alternatively, using CSS without Tailwind also comes with this drawback as well, where you would need to go through many lines of code to find what you're looking for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;
      &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;border-b-2 text-4xl pb-1 pt-8 mb-8 hover:pb-3 hover:ease-in hover:duration-300 min-[2400px]:text-8xl min-[2400px]:leading-[6rem]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLButtonElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MouseEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;buttonProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;buttonProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I already mentioned Tailwind's specificity and how it provides the convenience of not worrying about managing your own CSS specificities. However, this does come with one drawback, and that is being unable to switch the specificities of the Tailwind code without using the important (!) option. While that may not seem like too much of a drawback, for some developers, they may not want to include the important (!) option in their CSS no matter what.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall my experience was very positive and I am glad that I tried using Tailwind. I will be using Tailwind again for my future projects, but I do want to go back to using CSS without Tailwind from time to time to keep my skills as a CSS magician. 🪄 It saves so much time when initially building your application, and can be very convenient to use. However, I do not regret sticking with pure CSS for as long as I did because I was able to learn from that experience as well. I'm looking forward to learning more about what Tailwind provides!&lt;/p&gt;

&lt;p&gt;Tailwind documentation: &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;https://tailwindcss.com/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Conquering Fears: A Guide to an Empowered Developer Journey</title>
      <dc:creator>Richard Choi</dc:creator>
      <pubDate>Tue, 27 Aug 2024 18:20:05 +0000</pubDate>
      <link>https://forem.com/choir241/conquering-fears-a-guide-to-an-empowered-developer-journey-20ib</link>
      <guid>https://forem.com/choir241/conquering-fears-a-guide-to-an-empowered-developer-journey-20ib</guid>
      <description>&lt;p&gt;Over the years, I have experienced and overcome many of my fears. But the scariest part wasn't experiencing it; it was before I tried, the anticipation of it, the unknown factor of it all, not being able to control or know what's going to happen next. That's what filled me with the most fear before plunging in, only to discover it wasn't as bad as I thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://that.us/" rel="noopener noreferrer"&gt;THAT Conference&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Recently, I overcame one of my biggest fears at a tech conference called &lt;a href="https://that.us/" rel="noopener noreferrer"&gt;THAT&lt;/a&gt;. Before, I was traumatized as both a kid and a young teenager from riding rollercoasters. I became terrified of them and still am terrified of them. I was always the designated bag holder, watching my friends go through the lines.&lt;/p&gt;

&lt;p&gt;It wasn't until I was at the top of the stairs of an AquaLoop, a ride where you're loaded in a chamber that drops the platform beneath you into a vertical water slide, that my fear and anxiety started to kick in. My friends noticed this behavior and asked if I was okay, so I responded honestly: "No, but I want to experience this."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m6of7juwb4tiezanzqk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m6of7juwb4tiezanzqk.jpeg" alt="Man about to drop in the Aquadrop as the employee oversees for safety." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My heart was beating out of my chest, my stomach was running laps, my head was spinning, and I was gripping my arms so hard it felt like a boa constrictor had its scaley grip on me. My friends did one final check on me, which I reassured them. But perhaps I was lying to them and myself. A part of me was screaming to leave, to run down those long flights of stairs back to safety and comfort.&lt;/p&gt;

&lt;p&gt;But I was determined. So I walked up and hesitantly put one foot after another onto the cold platform.  As the glass door surrounded me, I felt my breath becoming shallower as I crossed my arms and legs.  I felt myself plunging into a spiral of emotions that left me dizzy and nauseous.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwxsqrixcypj1tu0lmilz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwxsqrixcypj1tu0lmilz.gif" alt="Candace Flynn from Phineas and Ferb Tv series dizzy with stars orbiting her head." width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The drop was sudden and fast. It happened before I could reasonably understand what was happening. Left and right, I turned as the speed of the water blew straight into my hair. I felt weightless at first, with nothing to support me but my arms and the icy steel of the slide against my back. Then I felt myself sliding into the water pool at a speed that would make Sonic the Hedgehog jealous. It was finally over.&lt;/p&gt;

&lt;p&gt;But the strange part was that I didn't hate any of it. In fact, it was quite enjoyable. Although I did hurt my left ankle, and the back of my head felt like it was hit at least 10-15 times, I felt relieved that I was encouraged to participate in this ride. One of my friends started to apologize for encouraging me to try the ride, but I assured them I enjoyed my experience. Looking back at it now, I'm grateful they encouraged me to experience something new.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjakr0zoqo1x70zja3wai.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjakr0zoqo1x70zja3wai.jpeg" alt="Kyouko Hori on the right wearing a sweatjacket holding cheerleading pom-poms looking straight to the left at Izumi Miyamura." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it was only because of the community around me that I was able to take that step forward.  Their encouragement and their displays of concern were what helped me get past my initial doubts and fears because I knew they were there for me.  Without them, I would have gone back to safety, back to the comforts of who I used to be, without ever really changing or challenging myself.  With a great and supportive community, you can really grow and change as a person.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community
&lt;/h2&gt;

&lt;p&gt;If it wasn't for my community, I definitely wouldn't be where I am today. I most likely would have gone back to my old, tiresome bank teller days and lived the rest of my days repetitively and listlessly being the same person every day.  It's thanks to my community that I was able to transform into a developer in the first place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Famsas1jd5weclm668j6m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Famsas1jd5weclm668j6m.gif" alt="A bright blue transforming into a piplup and pink ditto transforming into a pikachu." width="387" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To me, &lt;a href="https://100devs.org/" rel="noopener noreferrer"&gt;100Devs&lt;/a&gt; was a community first and a place to learn code and get a job second. The people in the &lt;a href="https://100devs.org/" rel="noopener noreferrer"&gt;100Devs&lt;/a&gt; community were and still are encouraging while remaining realistic, helping each other reach the finish line while striving for our goals and dreams. We helped each other overcome our own fears, like imposter syndrome or fear of not being able to land a developer job.&lt;/p&gt;

&lt;p&gt;For example, one of the assignments that was asked (not mandatory by any means) was to find our own freelance client and get paid money to build a web application. At first, this seemed like a terrifying expectation to reach. However, after all of us at &lt;a href="https://100devs.org/" rel="noopener noreferrer"&gt;100Devs&lt;/a&gt; received a lot of encouragement from Leon Noel, the founder of &lt;a href="https://100devs.org/" rel="noopener noreferrer"&gt;100Devs&lt;/a&gt;, I started on my unknown journey to finding my first freelance client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imposter Syndrome
&lt;/h2&gt;

&lt;p&gt;I had no idea where to begin, but I knew one thing: I was scared, and I wasn't sure what I was doing.  So I started off safe, going after forums like Reddit, Facebook, or Craigslist (yes, I know) to see if anyone was hiring a freelance web developer. Unfortunately, this process was fruitless, and I was slowly becoming more dispirited and discouraged as the days went by.  Deciding being passive wasn't good enough, I decided to be more active and post online on Facebook, Instagram, Twitter, LinkedIn, and Reddit to ask if anyone was looking for a web developer freelancer to hire.&lt;/p&gt;

&lt;p&gt;While I did find a few potential interested parties, they did not lead to anything fruitful.  I knew what I had to do, but knowing I would be receiving a lot of rejections was scary to imagine.  But I kept reminding myself that the other person on the phone was just a human being just like me - wearing clothes like me, brushing their teeth like me, and eating food like me.  So I went out and called as many local businesses in my area as I could that I found didn't have their own websites, or I felt I could improve their existing websites.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjf2oytog7tnvh84n1luj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjf2oytog7tnvh84n1luj.gif" alt="Kim Possible saying You can call me, or.. beep me. You know, if you wanna reach me to Ron Possible." width="498" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just as expected, there were a lot of rejections.  Most of them were short and abrupt, and there were a rare few that were also rude.  But I persisted. And as I continued, I found the process easier and less scary as I went on. I became more comfortable and felt more sure of myself. And I realized my initial fear was, in retrospect, kind of ridiculous compared to the imposter syndrome I was feeling from all the rejections.&lt;/p&gt;

&lt;p&gt;Receiving email job rejections was one thing, but hearing a rejection directly from another person's voice was another, especially when you do it one after another. I felt defeated and hopeless: it felt like I was walking in a heavy mist, tripping over every other step I took. But I was determined. I didn't want to give up, nor would I give up. So I continued, taking breaks here and there from all the rejections, and continued cold calling company after company.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzp3e25r6454b1xz583bw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzp3e25r6454b1xz583bw.gif" alt="Commander Tung from Mulan singing Let's get down to business." width="500" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And then it happened. I finally found that one phone call. It only took one, but all the imposter syndrome I was drowning myself in dissipated like a balloon releasing all its air. But then, a new fear started to arise, and I began to be afraid of the website's quality matching the client's expectations.  Even now, looking back at the current state of the website, I wonder if there was something I could have done better at the time.&lt;/p&gt;

&lt;p&gt;Each time I conquered a fear, it felt like a new fear started to form inside of me, and it felt scarier than the previous fear.  But everytime I conquered a fear, I also felt like I became a better developer and person, and those fears shaped the confidence that I was able to form.  And this wouldn't have happened if I didn't take the initiative to join the 100Devs community and find my freelance client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking Initiative
&lt;/h2&gt;

&lt;p&gt;When I was trying to get my first tech-related job, an advice I heard often from more experienced developers was "go out and network." And as someone who is on the more shy side, this was intimidating. The thought of reaching out to a complete stranger that I had never talked to and having a virtual video chat with them seemed like such a daunting idea at the time.&lt;/p&gt;

&lt;p&gt;I would be so nervous leading up to the actual video chat, feeling the pace of my heart speed up and progressively get louder. To mitigate my nervousness, I would write down questions I would ask to decrease the amount of silence in the chat itself. But because of this, I never really connected to the other person I was chatting with; I was too focused on having a coffee chat and networking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysqsabucgdjgass2k7ls.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysqsabucgdjgass2k7ls.gif" alt="Azusa Nakano from K-on anime" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But then I took the initiative to go to my first in-person meetup at NY Code and Coffee because I had always wanted to go to my first in-person developer meetup, but I was always afraid to travel to NYC by myself. When I connected with people outside of a screen, I realized I was connecting with people the incorrect way.&lt;/p&gt;

&lt;p&gt;I started to go to more NY Code and Coffee meetups to become more comfortable with connecting with people outside of screens.  As I took the initiative to keep talking to people both offline and online, I became better at conversations and communicating with others.  I also noticed that I became more confident in myself and became more sure of myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving Forward
&lt;/h2&gt;

&lt;p&gt;So take that initiative. Become more comfortable with being uncomfortable, and explore new experiences so you can grow in your journey as both as a person and as a developer. Go to your first conference, your first meetup, and experience new things like your first milkshake! And who knows, you could meet someone that will become your lifelong friend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34ram6rxdjafacv6hsyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F34ram6rxdjafacv6hsyc.png" alt="A picture of me, Richard Choi, experiencing their first milkshake ever." width="402" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My socials:&lt;br&gt;
&lt;a href="https://x.com/choir241" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/richard-choir/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
