<?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>DEV Community: Safak</title>
    <description>The latest articles on DEV Community by Safak (@safak).</description>
    <link>https://dev.to/safak</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%2F405573%2F5a2ae006-58c1-4149-a589-4b39bb686475.png</url>
      <title>DEV Community: Safak</title>
      <link>https://dev.to/safak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/safak"/>
    <language>en</language>
    <item>
      <title>Build Your Own Full Stack ChatGPT with React</title>
      <dc:creator>Safak</dc:creator>
      <pubDate>Thu, 25 Jul 2024 11:18:29 +0000</pubDate>
      <link>https://dev.to/safak/build-your-own-full-stack-chatgpt-with-react-5aoo</link>
      <guid>https://dev.to/safak/build-your-own-full-stack-chatgpt-with-react-5aoo</guid>
      <description>&lt;p&gt;Hi, I'm a full-stack web developer passionate about sharing my web development journey with other devs. I recently created a full-stack ChatGPT application that uses Gemini (I picked that over OpenAI because it's free). Check out my GitHub repository for the open-source code: &lt;a href="//github.com/safak/chatgpt-clone"&gt;Here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve also published the tutorial of the project on my YouTube channel: &lt;a href="https://youtu.be/8iAQ1h30n5I" rel="noopener noreferrer"&gt;You can check it out&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8iAQ1h30n5I"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What technologies are used?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Backend:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Express.js &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Database:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Auth:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clerk&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Frontend:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;React 19&lt;/li&gt;
&lt;li&gt;React Router Dom&lt;/li&gt;
&lt;li&gt;React Query&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Google Gemini&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Image Uploading:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ImageKit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The design consists of two layouts, five pages, and three components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;src&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;layouts&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RootLayout.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DashboardLayout.jsx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;routes&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Homepage.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DashboardPage.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ChatPage.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SignInPage.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SignOutPage.jsx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;components&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ChatList.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NewPrompt.jsx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Upload.jsx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;lib&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gemini.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up Google Gemini
&lt;/h2&gt;

&lt;p&gt;To integrate Google Gemini AI, we use the &lt;code&gt;@google/generative-ai&lt;/code&gt; library. Here is how to set it up in &lt;code&gt;gemini.js&lt;/code&gt;:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenerativeAI&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;@google/generative-ai&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;HarmBlockThreshold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HarmCategory&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;@google/generative-ai&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;safetySettings&lt;/span&gt; &lt;span class="o"&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;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HarmCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HARM_CATEGORY_HARASSMENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HarmBlockThreshold&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BLOCK_ONLY_HIGH&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;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HarmCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HARM_CATEGORY_HATE_SPEECH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HarmBlockThreshold&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BLOCK_MEDIUM_AND_ABOVE&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;genAI&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;GoogleGenerativeAI&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_GEMINI_API_KEY&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;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;genAI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGenerativeModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gemini-1.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;safetySettings&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;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up MongoDB Models
&lt;/h2&gt;

&lt;p&gt;Using Mongoose.js, we create schemas for our chats and user chats. This will allow us to verify upcoming CRUD inputs. Here are the schemas:&lt;/p&gt;

&lt;h3&gt;
  
  
  Chat Schema
&lt;/h3&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;chatSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;required&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="na"&gt;history&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;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;enum&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="s1"&gt;user&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="s1"&gt;model&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;required&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="na"&gt;parts&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;required&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="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;img&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;timestamps&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The history array is required to send previous data to the AI. This ensures that when we visit the chat page and ask a new question, we receive relevant answers. Additionally, using the userId, we can verify the owner of the chat.&lt;/p&gt;

&lt;h3&gt;
  
  
  UserChats Schema
&lt;/h3&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;userChatsSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;required&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="na"&gt;chats&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;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;required&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="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;required&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="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&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;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;timestamps&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each user has a &lt;code&gt;chats&lt;/code&gt; array that includes the title and ID of their chats. We’ll use the title to display items in the left menu, and when a user clicks on any of these titles, we’ll open the chat page using the corresponding ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an AI Chat
&lt;/h3&gt;

&lt;p&gt;After creating the endpoint in the Express app and fetching data in the client, you’ll be able to pass the previous history to the AI.&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;chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startChat&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;history&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chatHistory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;generationConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;maxOutputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// You can limit your tokens&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;After displaying the chat, you are ready to have a conversation with the AI. Take the text from a form and send it to AI.&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;add&lt;/span&gt; &lt;span class="o"&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;text&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="nf"&gt;setQuestion&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;accumulatedText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&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;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessageStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aiData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;aiData&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="p"&gt;:&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="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &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;chunk&lt;/span&gt; &lt;span class="k"&gt;of&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;stream&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;chunkText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;accumulatedText&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunkText&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;setAnswer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accumulatedText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;mutation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mutate&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;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="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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how to create a chat streaming with Gemini AI. To see how to save them to a database, you can check the source code or the &lt;a href="https://youtu.be/8iAQ1h30n5I" rel="noopener noreferrer"&gt;video tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope it was useful. If you want to learn more about web development and practice with real-world projects, you can check out my channel and other posts 😊&lt;/p&gt;

&lt;h6&gt;
  
  
  Lama Dev
&lt;/h6&gt;

&lt;p&gt;🔥 &lt;a href="https://www.youtube.com/c/lamadev" rel="noopener noreferrer"&gt;Lama Dev YouTube Channel&lt;/a&gt;&lt;br&gt;
❌ &lt;a href="https://x.com/lamaWebDev" rel="noopener noreferrer"&gt;Lama Dev X/Twitter&lt;/a&gt;&lt;br&gt;
⚡️ &lt;a href="https://www.instagram.com/lamawebdev" rel="noopener noreferrer"&gt;Lama Dev Instagram&lt;/a&gt;&lt;br&gt;
👾 &lt;a href="https://github.com/safak/chatgpt-clone" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>programming</category>
    </item>
    <item>
      <title>Next.js Full Stack Food Delivery App (5+ Hours Free Tutorial)</title>
      <dc:creator>Safak</dc:creator>
      <pubDate>Wed, 09 Aug 2023 12:37:50 +0000</pubDate>
      <link>https://dev.to/safak/nextjs-full-stack-food-delivery-app-5-hours-free-tutorial-1kg9</link>
      <guid>https://dev.to/safak/nextjs-full-stack-food-delivery-app-5-hours-free-tutorial-1kg9</guid>
      <description>&lt;p&gt;Hey, fellow developers!&lt;/p&gt;

&lt;p&gt;I'm a full-stack web developer with a passion for sharing my web development journey with other devs. Recently, I’ve created a full stack Restaurant application where users can order food. Feel free to check it out on my &lt;a href="https://github.com/safak/full-stack-restaurant"&gt;GitHub page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Moreover, I’ve published the tutorial of the project on my Youtube channel. You can reach the playlist &lt;a href="https://www.youtube.com/playlist?list=PLj-4DlPRT48l3EWFFPLD2ZxgSB0rnA8rO"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whether you're a seasoned developer or a curious learner, this tutorial series has something for everyone.&lt;/p&gt;




&lt;h2&gt;
  
  
  What technologies are used?
&lt;/h2&gt;

&lt;h5&gt;
  
  
  Backend:
&lt;/h5&gt;

&lt;p&gt;Next.js App Router (API)&lt;/p&gt;

&lt;h5&gt;
  
  
  Database:
&lt;/h5&gt;

&lt;p&gt;PostgreSQL (but you can choose any other database provider because we'll be using Prisma ORM)&lt;/p&gt;

&lt;h5&gt;
  
  
  Auth:
&lt;/h5&gt;

&lt;p&gt;Auth.js (Next-Auth) with Prisma Adapter&lt;/p&gt;

&lt;h5&gt;
  
  
  Payment Gateway:
&lt;/h5&gt;

&lt;p&gt;Stripe Custom Payments&lt;/p&gt;

&lt;h5&gt;
  
  
  Front-End Framework:
&lt;/h5&gt;

&lt;p&gt;Next.js App Router (Pages)&lt;/p&gt;

&lt;h5&gt;
  
  
  UI libraries:
&lt;/h5&gt;

&lt;p&gt;Tailwind CSS&lt;/p&gt;

&lt;h5&gt;
  
  
  State Management Library:
&lt;/h5&gt;

&lt;p&gt;Zustand&lt;/p&gt;

&lt;h5&gt;
  
  
  File Storage:
&lt;/h5&gt;

&lt;p&gt;Cloudinary&lt;/p&gt;




&lt;h2&gt;
  
  
  Design Part of the Restaurant App
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gXlcwtS40LA"&gt;
&lt;/iframe&gt;
&lt;br&gt;
In this part, we’ll design the application using reusable React components and Tailwind CSS. It’s a great tutorial to understand the difference between Next.js server-side components and client-side components. You’ll also learn how to design a fully responsive app using Tailwind classes.&lt;/p&gt;

&lt;p&gt;The design consists of seven pages and ten components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;src&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;app&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;page.tsx (Homepage)&lt;/li&gt;
&lt;li&gt;cart

&lt;ul&gt;
&lt;li&gt;page.tsx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;login

&lt;ul&gt;
&lt;li&gt;page.tsx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;menu

&lt;ul&gt;
&lt;li&gt;page.tsx&lt;/li&gt;
&lt;li&gt;[categoryId]

&lt;ul&gt;
&lt;li&gt;page.tsx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;orders

&lt;ul&gt;
&lt;li&gt;page.tsx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;product

&lt;ul&gt;
&lt;li&gt;[id]

&lt;ul&gt;
&lt;li&gt;page.tsx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;components&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;CartIcon.tsx&lt;/li&gt;
&lt;li&gt;CountDown.tsx&lt;/li&gt;
&lt;li&gt;Featured.tsx&lt;/li&gt;
&lt;li&gt;Footer.tsx&lt;/li&gt;
&lt;li&gt;Navbar.tsx&lt;/li&gt;
&lt;li&gt;Menu.tsx&lt;/li&gt;
&lt;li&gt;Notification.tsx&lt;/li&gt;
&lt;li&gt;Offer.tsx&lt;/li&gt;
&lt;li&gt;Price.tsx&lt;/li&gt;
&lt;li&gt;Slider.tsx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Full Stack Part of the Food Ordering App
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/aYzT06aQkGI"&gt;
&lt;/iframe&gt;
&lt;br&gt;
In this part, we’ll create the API route and communicate with the front end. I preferred PostgreSQL, but as I mentioned above, you can use any other database because we won’t write a single line of SQL code thanks to Prisma. We’ll make all the CRUD operations using Prisma Client easily.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;src&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;app&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;api

&lt;ul&gt;
&lt;li&gt;create-intent

&lt;ul&gt;
&lt;li&gt;route.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;confirm

&lt;ul&gt;
&lt;li&gt;route.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;categories

&lt;ul&gt;
&lt;li&gt;route.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;orders

&lt;ul&gt;
&lt;li&gt;route.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;products

&lt;ul&gt;
&lt;li&gt;route.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;auth
-[…nextAuth]

&lt;ul&gt;
&lt;li&gt;route.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;docker&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;docker-compose.yml&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;utils&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;auth.ts&lt;/li&gt;
&lt;li&gt;connect.ts&lt;/li&gt;
&lt;li&gt;store.ts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the authentication, we’ll be using &lt;em&gt;Next-Auth Prisma Adapter&lt;/em&gt; and it’ll handle all the auth process including sessions, user accounts, tokens, role based authorizations etc. &lt;/p&gt;

&lt;p&gt;To do that, you need to create a schema file in prisma/schema.prisma similar to this one:&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="nx"&gt;datasource&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgresql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;shadowDatabaseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SHADOW_DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Only needed when using a cloud provider that doesn't support the creation of new databases, like Heroku. Learn more: https://pris.ly/d/migrate-shadow&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;generator&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prisma-client-js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;previewFeatures&lt;/span&gt; &lt;span class="o"&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;referentialActions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// You won't need this in Prisma 3.X or higher.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;                 &lt;span class="nb"&gt;String&lt;/span&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;id&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cuid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="nx"&gt;userId&lt;/span&gt;             &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;               &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="nx"&gt;provider&lt;/span&gt;           &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="nx"&gt;providerAccountId&lt;/span&gt;  &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="nx"&gt;refresh_token&lt;/span&gt;      &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;
  &lt;span class="nx"&gt;access_token&lt;/span&gt;       &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;
  &lt;span class="nx"&gt;expires_at&lt;/span&gt;         &lt;span class="nx"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;token_type&lt;/span&gt;         &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;scope&lt;/span&gt;              &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;id_token&lt;/span&gt;           &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;
  &lt;span class="nx"&gt;session_state&lt;/span&gt;      &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

  &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;references&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;onDelete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cascade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="p"&gt;@@&lt;/span&gt;&lt;span class="nd"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;providerAccountId&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;Session&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;           &lt;span class="nb"&gt;String&lt;/span&gt;   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;id&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cuid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="nx"&gt;sessionToken&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;unique&lt;/span&gt;
  &lt;span class="nx"&gt;userId&lt;/span&gt;       &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="nx"&gt;expires&lt;/span&gt;      &lt;span class="nx"&gt;DateTime&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;         &lt;span class="nx"&gt;User&lt;/span&gt;     &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;references&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;onDelete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cascade&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;model&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;id&lt;/span&gt;            &lt;span class="nb"&gt;String&lt;/span&gt;    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;id&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cuid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;          &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;email&lt;/span&gt;         &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;unique&lt;/span&gt;
  &lt;span class="nx"&gt;emailVerified&lt;/span&gt; &lt;span class="nx"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;isAdmin&lt;/span&gt;       &lt;span class="nb"&gt;Boolean&lt;/span&gt;   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;image&lt;/span&gt;         &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
  &lt;span class="nx"&gt;accounts&lt;/span&gt;      &lt;span class="nx"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;sessions&lt;/span&gt;      &lt;span class="nx"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="nx"&gt;VerificationToken&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;identifier&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
  &lt;span class="nx"&gt;token&lt;/span&gt;      &lt;span class="nb"&gt;String&lt;/span&gt;   &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;unique&lt;/span&gt;
  &lt;span class="nx"&gt;expires&lt;/span&gt;    &lt;span class="nx"&gt;DateTime&lt;/span&gt;

  &lt;span class="p"&gt;@@&lt;/span&gt;&lt;span class="nd"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&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;We use this standard schema for the Prisma adapter; you can find it in the &lt;a href="https://authjs.dev/reference/adapter/prisma"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve only added the &lt;em&gt;isAdmin&lt;/em&gt; field in the user model to give a role for users. I use a boolean because my application has only two roles (admin/regular user). &lt;/p&gt;

&lt;p&gt;Source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.lama.dev/role-based-auth-prisma-next-auth/"&gt;Role-Based Authentication with Next.js and Prisma&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After completing the authentication and CRUD operations, we’ll start adding the cart functionality. In the project, &lt;em&gt;Zustand&lt;/em&gt; was my preference for state management. &lt;/p&gt;

&lt;p&gt;If you prefer a simple and concise state management solution, Zustand might be a better fit.&lt;/p&gt;

&lt;p&gt;Creating a Zustand store is as simple as calling a single function, passing a function that defines the store’s initial state and actions. &lt;/p&gt;

&lt;p&gt;Source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.lama.dev/zustand-state-management-tool/"&gt;Learn more about Zustand&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And finally, we’ll implement Stripe custom payments with the shipping option, and users will be able to create new orders and complete the payment process.&lt;/p&gt;

&lt;p&gt;I hope it was useful. If you want to learn more about web development and practice with real-world projects, you can check out my channel and other posts.&lt;/p&gt;

&lt;h6&gt;
  
  
  Other Dev.to Posts
&lt;/h6&gt;

&lt;p&gt;🎥 &lt;a href="https://dev.to/safak/full-stack-youtube-clone-5-hours-free-tutorial-2kfg"&gt;Full Stack Youtube Clone (5 hours free tutorial)&lt;/a&gt;&lt;br&gt;
🛍️ &lt;a href="https://dev.to/safak/full-stack-e-commerce-app-8-hours-free-tutorial-10pb"&gt;Full Stack E-Commerce App (+8 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
📺 &lt;a href="https://dev.to/safak/full-stack-netflix-app-7-hours-free-tutorial-1o6l"&gt;Full Stack Netflix App (+7 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
🧑‍🤝‍🧑 &lt;a href="https://dev.to/safak/social-media-app-using-mern-stack-4ic6"&gt;Full Stack Social Media App (+7 Hours free tutorial)&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Lama Dev
&lt;/h6&gt;

&lt;p&gt;🔥 &lt;a href="https://www.youtube.com/c/lamadev"&gt;Lama Dev YouTube Channel&lt;/a&gt;&lt;br&gt;
⚡️ &lt;a href="https://www.instagram.com/lamawebdev"&gt;Lama Dev Instagram&lt;/a&gt;&lt;br&gt;
👾 &lt;a href="https://github.com/safak/full-stack-restaurant"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Full Stack Youtube Clone (5 hours free tutorial)</title>
      <dc:creator>Safak</dc:creator>
      <pubDate>Sun, 17 Jul 2022 11:35:59 +0000</pubDate>
      <link>https://dev.to/safak/full-stack-youtube-clone-5-hours-free-tutorial-2kfg</link>
      <guid>https://dev.to/safak/full-stack-youtube-clone-5-hours-free-tutorial-2kfg</guid>
      <description>&lt;p&gt;Hi friends, I'm Safak. I am a full-stack web developer and I'm sharing open source web projects on my dev blog and their tutorials on my YouTube channel. I've shared 3 full-stack projects so far and I want to share my 5 hours "Full Stack Video Sharing App" tutorial for free. You can find the playlist &lt;a href="https://youtube.com/playlist?list=PLj-4DlPRT48mDB819AYgn3mQoTfCuheCX"&gt;here&lt;/a&gt;. &lt;/p&gt;




&lt;h2&gt;
  
  
  What technologies are used?
&lt;/h2&gt;

&lt;h5&gt;
  
  
  Backend:
&lt;/h5&gt;

&lt;p&gt;Node.js Express Framework&lt;/p&gt;

&lt;h5&gt;
  
  
  Database:
&lt;/h5&gt;

&lt;p&gt;MongoDB, Firebase&lt;/p&gt;

&lt;h5&gt;
  
  
  Auth:
&lt;/h5&gt;

&lt;p&gt;JWT, Cookies, Firebase Google Auth&lt;/p&gt;

&lt;h5&gt;
  
  
  Front-End Framework:
&lt;/h5&gt;

&lt;p&gt;React.js with hooks&lt;/p&gt;

&lt;h5&gt;
  
  
  UI library:
&lt;/h5&gt;

&lt;p&gt;Styled Components&lt;/p&gt;

&lt;h5&gt;
  
  
  State Management Library:
&lt;/h5&gt;

&lt;p&gt;Redux&lt;/p&gt;

&lt;h5&gt;
  
  
  File Storage:
&lt;/h5&gt;

&lt;p&gt;Firebase Storage&lt;/p&gt;




&lt;h2&gt;
  
  
  Design Part of the Video Sharing App
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/yIaXoop8gl4"&gt;
&lt;/iframe&gt;
&lt;br&gt;
In this part, I've designed a YouTube-like video sharing app using React.js functional components, hooks and Styled Components. For the layout I preferred using Flexbox.&lt;/p&gt;

&lt;p&gt;The app includes 4 pages and 7 small components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;src&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;pages&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Home.jsx&lt;/li&gt;
&lt;li&gt;Search.jsx&lt;/li&gt;
&lt;li&gt;Video.jsx&lt;/li&gt;
&lt;li&gt;SignIn.jsx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;components&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Card.jsx&lt;/li&gt;
&lt;li&gt;Comments.jsx&lt;/li&gt;
&lt;li&gt;Comment.jsx&lt;/li&gt;
&lt;li&gt;Menu.jsx&lt;/li&gt;
&lt;li&gt;Navbar.jsx&lt;/li&gt;
&lt;li&gt;Recommendation.jsx&lt;/li&gt;
&lt;li&gt;Upload.jsx&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Full Stack Part of the Youtube Clone
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CCF-xV3RSSs"&gt;
&lt;/iframe&gt;
&lt;br&gt;
In this part of the video, I've created an API using Node.js Express server with a MongoDB connection. Then created necessary models, routes and controllers in order to handle CRUD operations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;root&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;models&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;User.model.js&lt;/li&gt;
&lt;li&gt;Video.model.js&lt;/li&gt;
&lt;li&gt;Comment.model.js&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;routes&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;auth.js&lt;/li&gt;
&lt;li&gt;users.js&lt;/li&gt;
&lt;li&gt;videos.js&lt;/li&gt;
&lt;li&gt;comments.js&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;controllers&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;auth.controller.js&lt;/li&gt;
&lt;li&gt;user.controller.js&lt;/li&gt;
&lt;li&gt;video.controller.js&lt;/li&gt;
&lt;li&gt;comment.controller.js&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you realize, there is an additional route and controller to take care of user authentication. To provide a security I've used &lt;strong&gt;bcryptjs&lt;/strong&gt; and &lt;strong&gt;JWT&lt;/strong&gt; library with cookies in the auth controller.&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signin&lt;/span&gt; &lt;span class="o"&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="nx"&gt;next&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;user&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;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findOne&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="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;name&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User not found!&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;isCorrect&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;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compare&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;password&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;password&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isCorrect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Wrong Credentials!&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&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;_id&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;JWT&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;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;others&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;_doc&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="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;httpOnly&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="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;others&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;next&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, I've combined the API with the UI Design in order to make the application dynamic. To fetch data and make other API requests &lt;strong&gt;axios&lt;/strong&gt; was used and to handle state management, I preferred using &lt;strong&gt;redux-toolkit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I hope it was useful. If you want to learn more about web development and practice with real-world projects, you can check out my channel and other posts.&lt;/p&gt;

&lt;h6&gt;
  
  
  Other Dev.to Posts
&lt;/h6&gt;

&lt;p&gt;🛍️ &lt;a href="https://dev.to/safak/full-stack-e-commerce-app-8-hours-free-tutorial-10pb"&gt;Full Stack E-Commerce App (+8 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
📺 &lt;a href="https://dev.to/safak/full-stack-netflix-app-7-hours-free-tutorial-1o6l"&gt;Full Stack Netflix App (+7 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
🧑‍🤝‍🧑 &lt;a href="https://dev.to/safak/social-media-app-using-mern-stack-4ic6"&gt;Full Stack Social Media App (+7 Hours free tutorial)&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Lama Dev
&lt;/h6&gt;

&lt;p&gt;🔥 &lt;a href="https://www.youtube.com/c/lamadev"&gt;Lama Dev YouTube Channel&lt;/a&gt;&lt;br&gt;
⚡️ &lt;a href="https://www.facebook.com/groups/lamadev"&gt;Lama Dev Facebook&lt;/a&gt;&lt;br&gt;
👾 &lt;a href="https://github.com/safak/youtube2022/tree/fullstack-youtube-clone"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>React Testing For Beginners</title>
      <dc:creator>Safak</dc:creator>
      <pubDate>Mon, 11 Apr 2022 14:13:21 +0000</pubDate>
      <link>https://dev.to/safak/react-testing-for-beginners-1ak2</link>
      <guid>https://dev.to/safak/react-testing-for-beginners-1ak2</guid>
      <description>&lt;p&gt;Today, we are going to talk about one of the most underrated parts of development: &lt;strong&gt;Testing&lt;/strong&gt;. We all know testing is really important and a properly tested software product ensures dependability, security, and high performance, which leads to time savings, cost effectiveness, and customer satisfaction. But why do we underestimate testing even though it's not that challenging? &lt;/p&gt;

&lt;p&gt;"Because it's boring!" &lt;/p&gt;

&lt;p&gt;It's true. Nobody wants to be a goalkeeper instead of dancing with the ball on the field as other players do. However, you need to be aware of how much time you can waste with a faulty project. You think you've completed the product, but it comes back to you again and again. You have to check components, you have to find where the problem is. And without testing, you'll never know if it's working properly. If that sounds overwhelming enough, let's get started and see how we can test our React applications.&lt;/p&gt;

&lt;p&gt;For a better understanding, you can watch the video version of the tutorial. It'll be more useful for beginners. Here it is:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Flo268xRpV0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Reading is better? Let's continue.&lt;/p&gt;

&lt;p&gt;Firstly we need a testing library to reach DOM elements and interact with them, and need a testing framework that we can compare the test result with the real result. In this tutorial, we'll use @testing-library/react and jest. If you are using create-react-app, you don't have to install anything, the app already includes them. If you don't use create-react-app, you should run the following line.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install --save-dev @testing-library/react jest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's try to understand, how it works. To do that, we'll add some HTML elements in App.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {

  const a = 2
  const b = 4

  return (
    &amp;lt;div className="app"&amp;gt;      
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;Apple&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;Banana&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;Orange&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;

      &amp;lt;h1 data-testid= "title"&amp;gt;Hello&amp;lt;/h1&amp;gt;
      &amp;lt;span title="sum"&amp;gt;{a+b}&amp;lt;/span&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our goal is testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether the fruit list includes 3 items,&lt;/li&gt;
&lt;li&gt;whether the h1 tag exists,&lt;/li&gt;
&lt;li&gt;whether the span tag contains the sum of variables a and b.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's open &lt;strong&gt;App.test.js&lt;/strong&gt; file and start out tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 1
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The first thing we need to do is create a new test and giving a description.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test('should render 3 list items', () =&amp;gt; {

});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Okey. We've described our goal. And now, we should reach DOM elements to select list items. To do that we are going to use &lt;strong&gt;render&lt;/strong&gt; method of React testing library, and render our component.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { render } from '@testing-library/react';
import App from './App';

test('should render 3 list items', () =&amp;gt; {
  render(&amp;lt;App /&amp;gt;);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now we are ready to select list items to check their length. To select any DOM element we'll use &lt;a href="https://testing-library.com/docs/queries/about"&gt;React testing library queries&lt;/a&gt;. You have many options to do that. Let's use &lt;a href="https://testing-library.com/docs/queries/byrole"&gt;role based query&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { render, screen } from '@testing-library/react';
import App from './App';

test('should render 3 list items', () =&amp;gt; {
  render(&amp;lt;App /&amp;gt;);
  const listitems = screen.getAllByRole("listitem");
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Since we have more than one listitem, we don't use &lt;code&gt;getBy&lt;/code&gt;, we use &lt;code&gt;getAllBy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;** &lt;strong&gt;screen&lt;/strong&gt; object represents the entire HTML document in the rendered component.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, we can compare the result using Jest. To to that, we'll write our expectation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { render, screen } from '@testing-library/react';
import App from './App';

test('should render 3 list items', () =&amp;gt; {
  render(&amp;lt;App /&amp;gt;);
  const listitems = screen.getAllByRole("listitem");
  expect(listitems).toHaveLength(3);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** When you're writing tests, you often need to check that values meet certain conditions. expect gives you access to a number of "matchers" that let you validate different things. To see all &lt;code&gt;expect&lt;/code&gt; methods, &lt;a href="https://jestjs.io/docs/expect"&gt;you can check here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And. That's all. Let's check the test result.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm run test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And as you realize, the test passes. Congratulations. Now you can change the list item number and see how it fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 2
&lt;/h2&gt;

&lt;p&gt;In this test, we are going to check whether the h1 tag exists or not. And to select h1 item we'll use another query.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;h1 data-testid= "title"&amp;gt;Hello&amp;lt;/h1&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This time we are using a test id to identify h1 tag. Let's use it and select the item and check for its existence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { render, screen } from '@testing-library/react';
import App from './App';

test('title should be rendered', () =&amp;gt; {
  render(&amp;lt;App /&amp;gt;);
  const title = screen.getByTestId("title");
  expect(title).toBeInTheDocument();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's that easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test 3
&lt;/h2&gt;

&lt;p&gt;In the last test we are going to check the sum of variables. &lt;br&gt;
&lt;code&gt;a = 2&lt;/code&gt;&lt;br&gt;
&lt;code&gt;b = 4&lt;/code&gt;&lt;br&gt;
And we are expecting 6. Let me show you another testing library query.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;span title="sum"&amp;gt;{a+b}&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we are using another identifier which is &lt;code&gt;title&lt;/code&gt;. Let's use it and select the item and check the total number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { render, screen } from '@testing-library/react';
import App from './App';

test('sum should be 6', () =&amp;gt; {
  render(&amp;lt;App /&amp;gt;);
  const sum = screen.getByTitle("sum");
  expect(sum.textContent).toBe("6")
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now, we have 3 successful tests. Of course you can use other expect methods. It's really flexible. Let's try another method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { render, screen } from '@testing-library/react';
import App from './App';

test('sum should be 6', () =&amp;gt; {
  render(&amp;lt;App /&amp;gt;);
  const sum = screen.getByTitle("sum");
  expect(sum).toHaveTextContent("6")
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It'll give us the same result. You can also try another alternatives in Jest documentation.&lt;/p&gt;

&lt;p&gt;Now, you are able to create other basic tests on your own :) If you want to learn more advanced concepts and see how to test a real world example you should definitely check my &lt;a href="https://youtu.be/Flo268xRpV0"&gt;React testing crash course video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope it was useful. Thanks for reading :)&lt;/p&gt;

&lt;p&gt;✨ &lt;a href="https://dev.to/safak"&gt;My other posts&lt;/a&gt;&lt;br&gt;
🔥 &lt;a href="https://www.youtube.com/c/lamadev"&gt;Lama Dev YouTube Channel&lt;/a&gt;&lt;br&gt;
⚡️ &lt;a href="https://www.facebook.com/groups/lamadev"&gt;Lama Dev Facebook&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Full Stack E-Commerce App (+8 hours free tutorial)</title>
      <dc:creator>Safak</dc:creator>
      <pubDate>Tue, 12 Oct 2021 14:11:38 +0000</pubDate>
      <link>https://dev.to/safak/full-stack-e-commerce-app-8-hours-free-tutorial-10pb</link>
      <guid>https://dev.to/safak/full-stack-e-commerce-app-8-hours-free-tutorial-10pb</guid>
      <description>&lt;p&gt;Hi, I'm Safak. I am a full-stack web developer and I'm sharing open source web projects on my YouTube channel. I want to share my +8 hours "MERN Stack E-Commerce App with an Admin Dashboard" tutorial for free. You can reach the playlist from &lt;a href="https://www.youtube.com/watch?v=c1xTDSIXit8&amp;amp;list=PLj-4DlPRT48mxPG8TAXOH4qqQ1ijuERO4"&gt;here&lt;/a&gt;. &lt;/p&gt;




&lt;h2&gt;
  
  
  What technologies are used?
&lt;/h2&gt;

&lt;h6&gt;
  
  
  Backend Server: Node.js Express Framework, JWT
&lt;/h6&gt;

&lt;h6&gt;
  
  
  Database: MongoDB
&lt;/h6&gt;

&lt;h6&gt;
  
  
  Payment Method: Stripe API
&lt;/h6&gt;

&lt;h6&gt;
  
  
  Front-End Framework: React.js with hooks
&lt;/h6&gt;

&lt;h6&gt;
  
  
  UI library: Styled Components
&lt;/h6&gt;

&lt;h6&gt;
  
  
  State Management Library: Redux
&lt;/h6&gt;




&lt;h2&gt;
  
  
  Design Part of the E-Commerce App
&lt;/h2&gt;

&lt;p&gt;In this section, we are going to design an e-commerce app using React.js functional components, hooks and Styled Components. For now, we are going to be using a dummy data to display products but in the last part we'll fetch all data from MongoDb using a Rest API&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/c1xTDSIXit8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Back-End Part of the E-Commerce App
&lt;/h2&gt;

&lt;p&gt;In this section, we are going to create a Rest API using Express server with MongoDB connection and create necessary models and routes in order to handle CRUD operations. We'll provide the security using JWT and authenticate and authorize users. And also you'll see how easy to get payment using Stripe API&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Router&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;stripe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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;stripe&lt;/span&gt;&lt;span class="dl"&gt;"&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;STRIPE_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;/payment&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="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="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;source&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;tokenId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;amount&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;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;usd&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="nx"&gt;stripeErr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stripeRes&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stripeErr&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="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stripeErr&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stripeRes&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;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/rMiRZ1iRC0A"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  MERN Stack Part of the E-Commerce App
&lt;/h2&gt;

&lt;p&gt;In this section, we are going to combine the API with the UI Design and make our application dynamic. We'll fetch data and make POST requests using &lt;strong&gt;axios&lt;/strong&gt;. And also we'll be covering &lt;strong&gt;Redux Toolkit&lt;/strong&gt; in depth.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSlice&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;@reduxjs/toolkit&lt;/span&gt;&lt;span class="dl"&gt;"&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;const&lt;/span&gt; &lt;span class="nx"&gt;productSlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSlice&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;product&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;isFetching&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//GET ALL&lt;/span&gt;
    &lt;span class="na"&gt;getProductStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;getProductSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;//DELETE&lt;/span&gt;
    &lt;span class="na"&gt;deleteProductStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;deleteProductSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&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="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;//UPDATE&lt;/span&gt;
    &lt;span class="na"&gt;updateProductStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;updateProductSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;//ADD&lt;/span&gt;
    &lt;span class="na"&gt;addProductStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;addProductSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isFetching&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/y66RgYMAgSo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I hope it was useful. If you want to learn more about web development and practice with real-world projects, you can check out my channel and other posts.&lt;/p&gt;

&lt;p&gt;📹 &lt;a href="https://dev.to/safak/full-stack-youtube-clone-5-hours-free-tutorial-2kfg"&gt;Full Stack Youtube Clone (5 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
📺 &lt;a href="https://dev.to/safak/full-stack-netflix-app-7-hours-free-tutorial-1o6l"&gt;Full Stack Netflix App (+7 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
🧑‍🤝‍🧑 &lt;a href="https://dev.to/safak/social-media-app-using-mern-stack-4ic6"&gt;Full Stack Social Media App (+7 Hours free tutorial)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔥 &lt;a href="https://www.youtube.com/c/lamadev"&gt;Lama Dev YouTube Channel&lt;/a&gt;&lt;br&gt;
⚡️ &lt;a href="https://www.facebook.com/groups/lamadev"&gt;Lama Dev Facebook&lt;/a&gt;&lt;br&gt;
👾 &lt;a href="https://github.com/safak/youtube/tree/mern-ecommerce-app"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>Full Stack Netflix App (7 hours free tutorial)</title>
      <dc:creator>Safak</dc:creator>
      <pubDate>Thu, 29 Jul 2021 18:55:43 +0000</pubDate>
      <link>https://dev.to/safak/full-stack-netflix-app-7-hours-free-tutorial-1o6l</link>
      <guid>https://dev.to/safak/full-stack-netflix-app-7-hours-free-tutorial-1o6l</guid>
      <description>&lt;p&gt;Hi, I'm Safak. I am a full-stack web developer and I'm sharing open source web projects on my YouTube channel. After &lt;a href="https://dev.to/safak/social-media-app-using-mern-stack-4ic6"&gt;Full Stack Social Media App&lt;/a&gt; project, I decided to share my 7 hours "MERN Stack Netflix Clone with an Admin Panel" tutorial. &lt;/p&gt;

&lt;p&gt;For this project I used Express API, MongoDB, React functional components, hooks with context API. I hope you will enjoy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Part of the Netflix App
&lt;/h2&gt;

&lt;p&gt;In this section, we are going to design Netflix clone using React.js and Sass.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/FzWG8jiw4XM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  MERN Stack Part
&lt;/h2&gt;

&lt;p&gt;In this section, we are going to create an Express server with the MongoDB connection. And we are going to make API requests on the client side using axios, hooks and context API.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/tsNswx0nRKM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I hope it was useful. If you want to learn more about web development and practice with real-world projects, you can check my channel out.&lt;/p&gt;

&lt;p&gt;📹 &lt;a href="https://dev.to/safak/full-stack-youtube-clone-5-hours-free-tutorial-2kfg"&gt;Full Stack Youtube Clone (5 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
🛍️ &lt;a href="https://dev.to/safak/full-stack-e-commerce-app-8-hours-free-tutorial-10pb"&gt;Full Stack E-Commerce App (+8 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
🧑‍🤝‍🧑 &lt;a href="https://dev.to/safak/social-media-app-using-mern-stack-4ic6"&gt;Full Stack Social Media App (+7 Hours free tutorial)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔥 &lt;a href="https://www.youtube.com/c/lamadev"&gt;Lama Dev YouTube Channel&lt;/a&gt;&lt;br&gt;
⚡️ &lt;a href="https://www.facebook.com/groups/lamadev"&gt;Lama Dev Facebook&lt;/a&gt;&lt;br&gt;
👾 &lt;a href="https://github.com/safak/youtube/tree/mern-netflix-app"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>React Instant Chat App Using Node.js and Socket.io</title>
      <dc:creator>Safak</dc:creator>
      <pubDate>Wed, 26 May 2021 10:00:07 +0000</pubDate>
      <link>https://dev.to/safak/react-instant-chat-app-using-node-js-and-socket-io-5c7k</link>
      <guid>https://dev.to/safak/react-instant-chat-app-using-node-js-and-socket-io-5c7k</guid>
      <description>&lt;p&gt;Hi, I published a post and shared my 9 hours free social media application tutorial for free. But I decided to separate the application part and the chat server part. That because some of you people have already known how to create a MERN Stack application but struggle with web socket applications.&lt;/p&gt;

&lt;p&gt;🔥 &lt;a href="https://dev.to/safak/social-media-app-using-mern-stack-4ic6"&gt;visit the full tutorial post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and, for those who finished the application part or just interested in the messenger part:&lt;/p&gt;

&lt;h1&gt;
  
  
  React Chat App Using Socket.io
&lt;/h1&gt;

&lt;p&gt;In this section, we are going to design a React messenger component and some additional routes in Node.js to get and post chat messages. And finally you are going to learn how to use Socket.io to send instant messages and notifications.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/HggSXt1Hzfk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I hope it was useful. If you want to learn more about web development and practice with real-world projects, you can check my channel out.&lt;/p&gt;

&lt;p&gt;🔥 &lt;a href="https://www.youtube.com/c/lamadev"&gt;Lama Dev Youtube Channel&lt;/a&gt;&lt;br&gt;
⚡️ &lt;a href="https://www.facebook.com/lamaWebDev"&gt;Lama Dev Facebook&lt;/a&gt;&lt;br&gt;
👾 &lt;a href="https://github.com/safak/youtube/tree/chat-app"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>socketio</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Social Media App Using MERN Stack</title>
      <dc:creator>Safak</dc:creator>
      <pubDate>Tue, 25 May 2021 19:58:21 +0000</pubDate>
      <link>https://dev.to/safak/social-media-app-using-mern-stack-4ic6</link>
      <guid>https://dev.to/safak/social-media-app-using-mern-stack-4ic6</guid>
      <description>&lt;p&gt;If you want to be a full-stack web developer and stuck at just beginner projects, here is the chance to improve your skills and create something real. I decided to share my 9 hours tutorial series on YouTube for free.&lt;/p&gt;

&lt;p&gt;We are going to create a social media application from scratch. And this project is not going to include just a basic couple of methods and an unpleasant design, it's going to include a complete web API, impressive React components, and chat functionality.&lt;/p&gt;

&lt;p&gt;Let's dive into it!&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating Node.js Rest API
&lt;/h1&gt;

&lt;p&gt;In this section, we are going to create an Express server and the MongoDB connection. You are going to learn how to create Models and Routes. And after the section, you will be able to create your own web API, login and register operations, and CRUD for users and posts.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ldGl6L4Vktk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Designing React Components
&lt;/h1&gt;

&lt;p&gt;In this section, we are going to design Facebook like website using reusable React components and React Hooks.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zM93yZ_8SvE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating MERN Stack Social Media App
&lt;/h1&gt;

&lt;p&gt;In this 3rd section, we are going to combine our Rest API and React UI design. You are going to learn real-world usage of a MERN application.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/pFHyZvVxce0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Realtime Chat App Using Socket.io
&lt;/h1&gt;

&lt;p&gt;I separated this part.&lt;br&gt;
⚡️ &lt;a href="https://dev.to/safak/react-instant-chat-app-using-node-js-and-socket-io-5c7k"&gt;Go to the messenger part&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope it was useful. If you want to learn more about web development and practice with real-world projects, you can check my channel out.&lt;/p&gt;

&lt;p&gt;📹 &lt;a href="https://dev.to/safak/full-stack-youtube-clone-5-hours-free-tutorial-2kfg"&gt;Full Stack Youtube Clone (5 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
🛍️ &lt;a href="https://dev.to/safak/full-stack-e-commerce-app-8-hours-free-tutorial-10pb"&gt;Full Stack E-Commerce App (+8 Hours free tutorial)&lt;/a&gt;&lt;br&gt;
📺 &lt;a href="https://dev.to/safak/full-stack-netflix-app-7-hours-free-tutorial-1o6l"&gt;Full Stack Netflix App (+7 Hours free tutorial)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔥 &lt;a href="https://www.youtube.com/c/lamadev"&gt;Lama Dev Youtube Channel&lt;/a&gt;&lt;br&gt;
⚡️ &lt;a href="https://www.facebook.com/lamaWebDev"&gt;Lama Dev Facebook&lt;/a&gt;&lt;br&gt;
👾 &lt;a href="https://github.com/safak/youtube/tree/mern-social-app"&gt;Source Code&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>mern</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
