Learn NEXT.JS 14 by Building The SnapChat App | TypeScript MongoDB Tailwind | Beginner Friendly

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to the course today we're building this SnapChat app with NEX js14 typescript OJs mongodb mongus kadary Tailwind CSS and Shaden this is the first nextjs 14 project in this channel that's why I will assume you're a complete beginner to nextjs and I will explain every single concept that we use in this application so that at the end of the course you will be able to build an application like this by yourself and I hate courses when they have long intros and I know you hate too so let me just showcase the app and then I will talk about the prerequisites for this course and then we will jump into the code so in this app there is a homepage that both authenticated and unauthenticated users can visit to learn what this app is all about I called it as snap nextext which is a Snapchat alternative for programmers you can share your code with your friends to get feedback and improve your code users can sign up and log in with their GitHub accounts once they sign in they will be redirected to the chat page where they can see their chat history and a camera to send a picture of their code alongside the images users can also send gifts that indicates if the code is okay not okay mindblowing funny on fire looks stupid and lovely and users can delete the entire chat history if they wanted to so this is the app that you'll have at the end of the day and I think it looks pretty cool but the only thing it's missing is real time messaging and to implement this real-time feature we need to add something like psycho which is not the focus of this course in this course we are trying to learn njs app router with its latest features things like server actions rout handlers layouts revalidating paths and more let me know in the comments if you'd like to see a full tutorial on building a realtime chat messaging app with next js14 so this has been the Showcase of the application now let's talk about the prerequisites I will assume you know the basics of react such as props components Hooks and state I will also assume you're familiar with CSS Basics such as flexbox but you don't need to know Tailwind CSS and chaten we will go over those in this course and of course you don't need to know nextjs 14 at all we will learn each concept as we could for the typescript part knowing the basics would be really helpful to follow this course but if you have never used it don't worry you can still follow along and when you get stuck you can ask it in our Discord server and we will try to help you and just a quick announcement before we get started we are trying to hit 100K subscribers by the end of 2024 this is not something easy it is actually pretty hard and it requires recording high value content consistently and I am willing to do that throughout this year so what will be incoming content and why should you subscribe well in every month I am planning to publish one or two courses and in every next course we will try to learn different concepts and tools so that at the end of the year when we get an interview we can talk about all these Concepts and tools that we learned and use to build these projects this is what I am planning to offer in 2024 and I am just expecting a bit of support from you thanks for subscribing and let's get started now so I have created an empty folder on my desktop and then I open it up in vs code so to get started with a nextjs application we can visit the docs and they give us this script or command that we can copy and paste it into our terminal so I will just paste it which is create next app at latest and I want this application to be in the current directory so I will just give one space and put a dot that is going to indicate that I want this to be in this root folder and then if you press enter it is going to ask us some questions and before we answer any of those so let's go to documentation and we ask some some questions so what is nextjs it is a react framework for building full stack web applications you use react components to build user interfaces and nextjs for additional features and optimizations so at the end of the day you are still writing react code but your uh application has been wrapped with nextjs layers or concepts that we should say and those layers are this additional features and optimizations so we have one list in the docs let's go one by one the first one is routing a file system based router built on top of server components and if you don't know what server components mean we're going to get there and then rendering is client site and server site rendering with client and server components and again we're going to get what client site and server site rendering means as well as what is client and server components then the data fetching so they provide us an extended fetch API for request memorization data caching and revalidation then it supports different styling methods including tailor and CSS and this is what we'll be using then images fonts and script optimizations to improve our web applications uh performance as well as the user experience and lastly typescript support out of the box which we'll be using in this app now let's go back to the terminal and answer some of those questions we would like to use typescript so let's say yes for this and we don't want to use eslint and if we don't know what that is it is a linter or in other words it is a program that analyzes your code to make sure your code is consistent in terms of styling and sometimes it can get a bit annoying so in this case we'll just say no at least in this tutorial and then we would like to use tailon CSS so they ask if you want to use the source directory so it doesn't really matter the only difference is it just puts your code into a source directory and in nextjs uh documentation they don't use this folder and that's what I'll be doing if you're following along make sure that you select no as well but as I said in terms of functionality it just doesn't matter if you select yes or no so we're going to go with no and then we would like to use the app router which is the latest one and recommend it so here there is something called import Alas and we don't want to customize the default one and it is this add symbol and if you don't understand we're going to get there as we could so let's say no for this and this is going to install all dep all dependencies and just initialize this app and let's wait for this once it is done we should see this success message and it is already been initialized a get repository for us as well so let's uh write mpm runev to start our development server and here we can see they just say visit Local Host in 3000 so let's go there and we should be able to see the initial uh thearter application that this commment gives us okay this is that initial application that we have in our uh so in our folder and let's take a look at the file and folder structure one by one so the first one is this next folder that has been ignored by git and this is a folder that you shouldn't be worrying about so it contains the compiled and optimized version of your nextjs application when you run mpm run build command nextjs takes your source code process it and generates the output in this nextt folder and it is typically autogenerated and it is not meant for direct modification and what that means is that you almost never interact with this folder and yeah it's been ignored by git already and then we have this app folder which is the place where the magic happens we're going to get there and then we have the public folder for as always just holding our static Assets in our case we have two svgs and in the app folder we have Fab icon our Global Styles which is used to initial initialize the tailwind and then we have two special files the first one is Page and let's take a look at that so since this is in the root uh of the app folder right it is directly inside the app not nested in any folders this is going to be the homepage so whatever you see in this content so let's just say hello from homepage that will be the homepage that we can see in this application so this is the change that we have now we are in the homepage so what happens if I wanted to create a page to let's say the login page if currently I visit this page I will get 404 because this page is not been created and to create one we we would go into the app folder create a folder and called login and then we need to create this special file so page. TSX and since we using typescript that's why this is being called TSX extension if you would use um uh JavaScript that would be JS or jsx so let's go with TSX Tex and to get the boiler plate code I have an extension called let's see es7 react um okay it's going to be this one you need to install this and you could type things like RFC or RFC e or RFC and that just gives you this uh Auto imported code so let's get this one and let's call it as login page we could save and if you visit now login page we can see this and let's create another one for sign up page so it is not going to be inside the login but rather in the app folder so let's say sign up and then page. TSX file okay so I have called it as sign up page if we save we could visit the sign up page and we would see that page but um so what happens if we wanted to have a page like sign up slash let's say something okay we would go ahead into the signup page and then create that something route and then that special file the page. TSX and let's say RFC uh something page now this is the thing that we can see when we visit this R okay I hope that the fundamental are clear now and we have the layout file as well so what is this layout file and let's just take a look at the documentation first so if I wanted to learn anything about nextjs I would visit nextjs dorg and then just search for it in this documentation and now I want to see the layout file and I will go to layout. JS and there we have it so the layout is a UI that is shared between routes and in our case we have the route layout in right if we visit that we can see this is the root layout that is directly inside the app folder and that's why it is called root and then let's see a root layout is the topmost uh topmost layout in the root app and it is used to define the HTML and body tags and other globally shared UI so let's see what that means we have the HTML and body tag of our website or web application and then we have the globally Shar UI so if the one use case would be if we wanted to have something like Navar and then our page content and then the footer right so that would be uh that would be the place that we would like to add it now let's save and now we should be able to see this SV bar and footer in all of our pages so in the homepage in the signup page login page and any other pages that we created because this is that uh UI so let's say say uh root or just layout is okay let's just put it in this way a layout is UI or let's say shared UI okay a layout is a shared UI and in this case this is the root layout that will be shared in our entire application let's visit our local host and if we go into the page of home page there we can see we have the Navar and then the page content and then the footer if you go into a page let's say sign up you would see the exact same structure navbar the page content and then the footer and this page content is this what we called the children that we are getting as the prop now let's visit the login page and the chances are we're going to get the exact same output the login page and even if we go into a page that does not exist that is 404 we still have the Navar then the 404 content and then the footer okay so that was the layout fun fundamentals but what happens if we wanted to have a layout that is shared between those two pages but not in other pages so not in the uh homepage not in any other any other pages but only in login and sign up so let's first delete the Navar in footer and what we would do is to put those two folders into another folder so in our case I will just create one folder let's call it oath and then I will put a login into there as well as so let's say uh update import for login and let's say yes and put this sign up into there as well um so sign up into oath okay so now here we could put a layout let's say layout. TSX and get it like this we could call this as let's say oath layout and then we have to get the children as prop and we're going to get a typescript error that says uh its type is any so let's say that this prop is getting a uh so this component is getting a prop which is the children field and the type of it is react. react Noe so if you have never used types script before this is for type safety that we say that this is the type of uh prop that we are getting right it is a react node and we would like to just render those children in this case it is going to be either the sign up page or the login page and we could say something like let's use tailin CSS so class name PG red 500 and that is going to give us the background color of uh this red color and at this point if you're not able to see this um so this classes when you hover over this or if you cannot get this auto complete so let's say I'll just say BG Dash and there we there we we go I just have a lot of Auto completes and if you can't get this it might be because of this extension so let's say Tailwind I think it was intellisense okay it is this one you have to install this and once you install that now we should be able to have the exact same behavior as mine and then okay so we could save this file and now what we are saying is that we are having a layout for our o Pages which is login and sign up and that contains this background uh background of red let's visit our signup page but now it is not going to work or the login page okay it says 404 it's because they are nested inside the oath page so now we have to go into a route like oath and then slash login and then we can see the login page and then we would like to go sign up page let's say sign up and this is the sign up page content and the background is this uh red color if you put something like it is going to be height of screen so if you hover over this it is uh height of 100 VH and there we have it this is the signup and login page and that's how you add additional or nested layouts other than root layout and if we go into the homepage we are not going to see this red background it is because this layout only affects the oath Pages it is inside the oath folder but the other layout so the root layout is that shared um shared UI globally because it was just the root that we explained a couple of seconds ago and but now we have this problem that I don't really want to first visit the oath page and then so let's say oath and login I don't want to type this oath first I just immediately want to go to the login page or let's say the signup page and in this case the solution is we wouldn't put them into the oath folder or instead we would just rename this to something like um so bracket oath and then bracket and in this case our app folder will just or app router will ignore this and this is just to group our folders and let's see okay it's going to take a bit time to rename this uh so rename this folder to bracket o that we can see here at the bottom let's wait for this okay so my vs code crashed and I just had to close it and open that up I'll just say um say mpm runev and then start our development server again then here we can see it has been renamed to O now we can safely visit the login Rod or signup rout without typing the O so let's refresh and here we have it now we could go to a page like log in and still we're getting this if we put something like SL o and login we're just going to get 404 because this page does not exist all just been ignored just because of this brackets and this is something called I guess um route grouping so let's say route okay it was this route groups and if you take a look at the documentation you can just see more examples so folder name is been unwrapped with this brackets so if I wanted to I could do the exact same thing for my homepage so I would create a folder and just wrap it with the brackets I could call it as root or home it doesn't really matter and then I would took my homepage that is inside the app folder and just drag and drop it into home and let's update the Imports for it and yeah this is the homepage that we have now let's go and visit so if we go into the rout it is still going to show us the homepage if we go to the home it is going to give us 404 because it has been ignored so this has been the rod groups and let's take a look at the layout. TSX so here we uh so here we are importing a font from next font and let's go into the docs and let's search for the font and here we can see next font will automatically optimize your phones and remove external network requests for improved privacy and performance and in our project we're using the inner Fone family but if you wanted to we could just get any of those so let's say Poppins or uh any of these phones that we can see here but in our case as we said it's going to be inner and we set it into this variable and we call this Latin sub subset and then um yeah then in the body we just say class name of our body will be this font family and we just call the class name property and then we have the meta data so again let's take a look at that in the docs so next sh has a metadata API that can be used to define your applications metadata for improved SEO and web shareability so to give an example it has this meta and Link tags inside your HTML head so let's take a look at that if we go to the homepage so we have create next app as our title and for the description um inside the meta tag okay it is this one generated by create next app and it is coming from the this metadata so we have the title and description so let's update this so the title will be snap next app and then the description could be something like Snapchat alternative for programmers built by nextjs if we save uh it should update the title as well as the description that we can see and lastly in our layout file we are importing our Global CSS file as well as giving this metadata to have this metadata type that is coming from next and this is something uh typescript specific and now that you understand the layout file let's go ahead and try to install a package called chat CN but before that first let's explain what is this so beautifully designed components that you can copy and paste into your apps it is accessible customizable and open source this is not a components Library it is a collection of free usable components that you can copy and paste into your apps so what do you mean by not a component Library so we do not install it as a dependency it is not available or distributed via mpm we pick the components that we need and copy and paste the code into our project and customize it as we need the code is ours and that's what makes sh CN just shine in like lately and uh let's go into the installation we want to use this inside the xjs app so let's select this now it says create a project project we already have one right we use this script let me just zoom in and we would like to run the shat cnii command so let's copy this and it is going to ask us these questions so let's go here open up a new terminal and then just paste this and wait for the questions okay the first one is would we like to use typescript yes and we can go with the default Styles we would like to just take the Slate as our base color and then where is our CSS file uh the global CSS it is under the app folder right inside the app we have the global and if you are using Source directory maybe you should have I mean you have to put Source before the app because your Source directory uh would contain the app but anyways let's uh select this one we would like to use CSS variables for colors and we do not want to so let's just skip this and be careful here so our Tailwind config.js file is not is not JS but rather it is TS so just press tab to get this file or the name and then just say TS at the end so let's uh select this one and we could again go with the uh components alas as well as the for the utils so it's going to create a components folder in the root and then the lip folder and utils folder in the route so let's select this one as well and we are using react server components and just press y for components. Json file and it's going to initialize our project and install all all the dependencies okay so we got this success message let's shrink this and there we can see we have the components folder which is empty for now whenever we install a component from Shaden it'll be put under this folder then we have the library folder which uh gets this utils TS file uh it is it is to use this Tailwind merge uh package in clsx so this is something that we shouldn't be worrying so we could uh close that and then we have the components. Json it has been created Again by Shaden and uh lastly it just uh overwrite our global. CSS file here we can see we have uh a couple of root colors as well as the dark uh mode colors then we have the tail with config.ru theme your colors now here if if I wanted to I could add a custom color so I'll just say uh my- custom- color and I'll just put some random value here maybe we could go with badass okay bad a55 and uh just put a comma here now we are able to use this color in our components so in my page I could go here and I'll just say uh BG will be oops smaller uh lowercase and then paste this now BG will be my custom color and now our file just recognize this let's go into the homepage there we go this is that color and this is the point of extending colors so here they are extending border radius key frames animations and I wanted to extend a couple of more colors from Snapchat that I took from their website so I will copy the Tailwind config TTS file and paste it into this um file okay so I'll just overwrite it and you can grab that in the GitHub preo as well so I could just put a note here okay so I just grab this file from GitHub preo and um yeah overwrite this and here we can see we have uh a couple of more colors for Snapchat uh blue and red and black color as well as uh we just put them as background colors so for hover State um yeah for hover State and just this colors that we can see and lastly we're going to have this background image uh we're going to be using two images which I will provide you again so for now just delete this public folder and then uh just put the folder that I will give you that you can grab from the GitHub so I have just saved this file and then took that public folder and then paste it into my app so here we can see we have a couple of svgs as well as this grainy background the hero background uh or the image then this this and then we have the logo so here I am using an extension to preview svgs and it is called let's see preview SVG and it is this one you have to install this to be able to preview your svgs so we have the chat SVG uh the GitHub the camera um yeah I think that's it and then we have a couple of more emojis so this one dislike fire laugh like love mind blown and question so we're going to be using all of these in the incoming sections so uh now that we got the public folder let's go ahead and try to uh build the homepage so first I'll just delete everything in this file other than the main tag so by the way this is the video of tailin CSS where we just write classes rather than uh so we just immediately put the utility classes so if I wanted to have this main to have the display Flex I just put it so now I can see this is a display flex and I could say Flex column and it's going to make the direction to be column and let's say what else items Center or let's say justify start and Center between and we could put something like pading X to be 12 right so we can get that or to padding y of 12 um or any value really we could see uh it just has different values that we could use and instead of so before tail in CSS we would do something like my class uh class name so you would put your class name here and then go into the global CSS or any CSS file then you would say my uh class name uh and then you would just say something like display of flex and flex direction to be colume um let's say padding you would give something like six fr and instead of doing that we just put that immediately into here or directly so we want our homepage to have a yellow background color so what I can do is say BG and then I have a couple of more yellow colors that I get from Tailwind but I don't want to use any of these so I want to give a custom color what I can do is this uh Square uh brackets and then hash FF fc0 so this is how we can put custom values between the square brackets you just put whatever you want to and now let's put something uh in between so hello from the homepage um let's go ahead and okay this page cannot be seen because I closed that so let's say mpm run Dev there was a problem off camera that's why I just shut it down uh but if we go now that should work so there we have it this is the homepage content and um so this is not a CSS course so we can't really be typing all the CSS classes and if you are someone that is able to follow this kind of full stack tutorial I just assume you are familiar with CSS classes and how CSS Basics works such as flexbox and that kind of stuff so that's why uh for the CSS part we would be copying and pasting code but it is not something that you should feel bad about because um it is only Style in and not logic at all so here I have one div that I'll just paste and close that off and this is going to be the main content for our homepage then uh there we can see it is the full screen it has Flex Flex column and item Center just by Center so the max width of 7x large which means that this is going to be kind of container and the maximum width will be this uh amount of pixels then we're just going to center it with MX Auto so you can just get this values from the Tailwind uh documentation let's just go ahead Tailwind CSS so I'm just explaining if you have never used it so that you could um maybe pause the video and take a look at the classes so let's say I wanted to learn about border radius I would just type it and here here I can see the classes as well as different examples so this is the rounded this is rounded full large medium and just feel free to uh interact with this uh docs now with that in mind let's go and create a navbar component now that we have the components folder we could put something like shared component and just put our shared component here in our case we will have the navb bar. TSX and again I will just get this code from um a GitHub gist and I'll just provide it to you so not in a GitHub gist but here I'll just paste this and then uncomment this and then at the bottom I will just paste it again so after the tutorial I'll just put the time stamp here so time stamp and when you take a look at the time stamp you'll understand ah okay so this is in the first hour we're using this and you could just copy that from the snapbar TSX file in the gab preo and then paste it into here okay so this is the exact same file I just uh double copied that now if you can see this file is broken it is because we're using the button component and we don't really have it also we're using this log out um logo so let's fix this now we said that we'll be using Shad CN and we are using the button component let's search for it and this is the button that you'll like to have so we could either copy this code and paste it um not this one but um okay so one way to install this code would be just um having this uh CLI command and then paste it so I think there also had the like the code that you would copy and paste um I couldn't see this for now but that's okay that's how I normally do and how you'll be doing so if you wanted to use button you would copy this command okay which is already copied this and go into our app open up a new terminal and then just paste it and it is going to import that into this components folder it's going to create a new folder called UI uh okay it is this one and we have our button component now we can go and uh press control space and import this uh from UI and button now here we talked about the import aliases uh at the beginning of the project so here what we can do instead of going double up so this looks a bit confusing so we could use something like add symbol which means now we are in the root of this folder right so when you put uh this add Sy symol now you're here exactly you're just in this folder you can go into app into components into lib there we can see we would like to go inside the components and then we have UI and then we'll s to import the button so this is that default alas when you use this you're in the root of the project now we have the button and let's import the log out um it is coming from this Lucid react uh icon library and it is being installed when we install the Shad CN so let's see where that is okay it's here and we could save this file and then import the Navar from the components shared in navbar um okay so let's save okay this is exactly the output that we would like to have we have a couple of buttons then logo and then uh these two buttons but now we don't really want to see this in the middle of the screen um but rather at the Top If we add more content it'll just move to top and after this Navar I will again copy and paste a bit of code okay so I have just copied that code and I will paste it first to here so I will just maybe un comment this copy again and I'll just say um Navar So Below the nav bar put this and the Tim stamp I will again after the tutorial we'll put the exact time stamp of this at this moment so that you can see okay this is the time you should copy and paste it okay so I'll just go ahead and paste that now we have the main tag um let's change this with div maybe and that could be our main tag so let's get a button from our components now here we have link we'll explain it is from next link and then we have the image which we already imported from next image and if we save this uh we using using the logo and let's take a look at the output and we're using this hero image so nothing complex we just have one Flex uh container and something on the left and something on the right so the hero there we can see it is uh the source is this hero.png and now if we carefully take a look at the image we are not using something like this image uh HTML tag but rather we're using this image component that is coming from from next and if you read the docks about it you will see that it is really being optimized and um so there are a lot of things they are doing under the hood so there are a couple of features for this image uh component there we can read from the docks and um like long story short it just makes it super optimized and the best image uh component that you can ever get so here we have to put width and height if you don't put it then it's going to complain um so let's wait it's actually going to give us some errors if we save this it is just not going to work it's going to say image uh has to have width and height so yeah if you don't put width and height you have another option which you should put fill that is going to make this image to fill the entire uh container which is this div in this case but you would like to give some width and height so I said uh 651 and 621 it is because uh this hero. PNG so let's see so it's aspect ra ratio is this 1302 and 1242 if we just divide it by two then we're going to get this aspect ratio it's basically the same thing so we just had to have it like this at least that's what they say in the docs so we have the image and we have the link so when we click to this login to explore button it is going to take us to the login route and again our image has some width and height let's save and now if I just test it out I'm going to click to this it's going to take us to the login page so this has been the homepage um so basically you would copy this code and paste it and everything just work magically and here we have this conditional check if now it is true but we're going to do something like const maybe oath um so this going to be our user when we implement the authentication for now we could just say if our user is authen authenticated then show this log to okay that should be actually if user is not authenticated then we'll just say log to explore right but since the oath is true then we just see this button that says start chatting and when you click that it's going to take you to the chat page and again we're going to create that once we get there but for now it just doesn't work so let's go ahead and Implement that login um login page so I have just copied the login page content and let's go into the oath the login I will delete everything from here paste it once and then let's just paste that twice and we could say the time stamp and again I will just put that so here if we comment uncomment this then we're going to get to this login component and let's go into the login page okay and we have to just delete this layout background color so that it doesn't look bad okay that this is this uh login card in the background looks really bad for now so let's just say BG slate maybe 100 or 900 say 700 or 600 and then we will just save this and there we go that looks a bit better but we're going to fix this and then we have to have a login card so let's create one component now we could really put that login card into our components folder but we're not going to use that login card other than this page so we instead of just having page component we could have other components as well so I'll just say login oops login card. TSX and I will copy the HTML markup and then paste it twice so the first one goes here and then the second one here and I'll just put the Tim stamp after the tutorial okay so we're going to uncomment this um there we can see we have a login Button as well that is just going to be after here okay so I'll just paste that login button below here as well so that you can have it okay so we have a form with this login button that has the image of GitHub SVG and then uh this sign up link that takes you to the sign up page and that says are you new to snap next let's save and we hopefully should see that if we add it to here uh the page okay um below this I think we'll just say login cart and import that paste it okay so it's not going to here but rather inside this div and here we have it when we collected this we're going to go into the signup page so let's again get the sign up page content so we're going to create one component sign up um- card. TSX and again let me just uh grab the content for those pages and components so copy it and paste it first and then once more I'll put the time stamp and then okay that is going to be it after this we'll just say import the signup card but first let's uh put it I I am copying that and put it into the signup card once and then twice okay we have the login Button as well um that's actually should be sign up button right so I'll just rename this as sign up button sign up button and rename this here and then I'll just copy this and paste it to here as well okay that's going to be our file and here inside the signup page let's get the sign up okay sign up cart and if we just save now you can see some classes like text will be x large font will be bolt text will be centered margin bottom of four and yeah this is basically CSS I don't I don't know feel that we should write the CSS code why should we waste any time and let me know in the comments if I think right or like wrong and just let me know if that should be the same approach we should do in the next tutorial or should we write all of this from scratch and okay so let's go into the sign up page that's says sign up to snap next and the button content is sign up and uh we could click to this and then go into the login page so now you might be wondering why are we copying and pasting the exact same code for two pages why don't we just add something like into the layout so yeah exactly let's just do that so we have the signup page and then the login page and this part is exactly the same as in in both of the pages so if you just put them side by side we have this div with flags flags column item Center and then this div and then this link uh with the image to that takes us to the homepage so why don't we just copy this so I'm going to delete I mean close that and then I'm going to just cut this okay and delete this part and just put this into a uh fragment and this is the only part that changes inside the login page and the sign up page so I will go into my layout and for now let's just paste that thing that we just copied so okay this is the thing that we have and let's close our div once and then twice let's import the link and then the image and so let's save to get this formatting and then we're just going to put the children so now in our login page we don't need to put this content or in the sign up page right so we just have the login card as well as the text now let's do the exact same thing for the signup page we could delete this and delete this part wrapid with a fragment so we don't get any errors but if we just save let's delete this Imports in both of those pages now that we should have the exact same behavior right so this is the signup page and this is the login page let's change the background in layout so if we say PG of um slate of let's say 600 we should get that background in both this page and then this page but this background doesn't look any good so let's try to change it if you go into the public folder from the GitHub uh you could see this noise SVG which is this background color or the background image that we'll be using and we're going to go into the Tailwind config.sys BG we could save this file and inside the layout instead of this background we'll just say BG oath Dash layout and if we save hopefully we should see that okay this is that uh the image and now we would like to add a gradient so let's wrap our layout with a div and then for the class name I'll just paste something so BG gradient to right from Slate 500 to Yellow 100 if we say save we are going to get this output and I think this looks a lot better and how to get this kind of greeny values so we would go to visit uh this website called uh I think yeah hypercolor dodev and you could change uh choose your colors and Direction so maybe to top left from this color uh let's say to create 600 and if we uh autogenerate it it's just going to give us different values or you could visit this screen Ian Tab and there are a lot of different values and you could just copy the TA in CSS classes for them and that's the website that I use to get this value and now that we have designed the sign up page the login page as well as the homepage we can go ahead and add the authentication but even before that we have to have a database so that we can save our users when they sign up and for this we're going to be using mongodb and now let's go ahead and set up a mongodb account and database and get started with it so to get started with mongodb we would go to mongod db.com and sign in into our account if you don't have already you should sign up it is free no credit card required so I'll just go ahead and log in so once you're logged in you will be redirected to this page if you don't have an organization I think you have to create one it is pretty simple and then now you'll like to create a new project Let's uh select this one and for the name I'll give something like Snap next and the owner will be me so let's create the project and then it is going to redirect us to this page now we would like to create a deployment and then we could go with the free tier which is pretty generous for site projects and let's try to create it and now we have to have a user so this is the username and the password for me I will copy this because we're going to be using it and let's create the user and then you have to add an IP address in this case it is added my IP address by default I will select finish and close and then it took us to this page where we would like to connect to our application so let's select the drivers and then we're going to get this uh script or this kind of mongod DP URI and I had my password so I will create inside the EMV let's add this EMV to get ignore so that has been ignored by git and we're adding this so that when we push our code to GitHub uh we can't so users can't see our environment variables so I'll just say mongod DB URI and that was my password I just paste it I'll use it and then we're going to copy this then paste it to here and then for the password we're going to replace it to here and this is the database name So currently we don't have anything if you don't put it is going to going to go inside the test database and create it but we would like to have a database let's call it as snap DB and we could save this now let's go here and we don't need to install mongod DP we are going to be using mongus to interact with our database so we could close this and that's going to be it for the database design one last thing that I want to add inside the network access I just want to add another IP address which is allow access from anywhere so that we don't get any potential errors during development and once we get into production we could change this list to our server so let's confirm this it's going to take a bit time to make it active once that is done we could go ahead and create our user schema and now that it's active let's go and do that we are going to store our models into a folder called models and the first model we'll have will be user model. TS now let's first Define this model in JavaScript way and then we're going to convert it to typescript let's first import the Mangus from Mangus and we need to install it so mpmi Mangus and it'll be done in the background now once we have it we would like to have a const user schema new mongus do schema that's going to be an object and now our users are going to have couple of fields the first one will be the username so let's say the type will be string and then it's going to be required as well as unique and then we're going to have the full name the type of string and required will be true and then one more field will be email so type string require true and then unique also will be true and lastly we're going to have the avatar and it'll be type of string and required now we don't have a password filled here it's because we're going to be using uh the GitHub provider so we don't use actually passwords and after this first object we could have another one for timestamps so let's say time Stamps will be true and this is going to give us that created that and updated that Fields let's put a comment okay the amongus will create it automatically for us and then we're going to go ahead and then just um create the model with this schema and then export it so let's say const user and mango. model and before we create this okay now that would normally would do so mango. model create a user model with the schema that we just defined but before that let's just check if we have this model already so Mangus the models if it has the user model if we have just use it if you don't have it just create it and this is typically going to run for the first time and then always this part will be true so it'll be assigned to this uh value and then let's say export default oops the user model now let's try to convert this into typescript the first thing that we'd like to have is going to be an interface so let's say export interface and the typical usage for interfaces is you put uh you just start with the I so this is the prefix that indicates this is actually an interface and then open up our object or the curl braces and the fields that we have in our user model so the username full name email and Avatar all of them are um so to say the type of string and let's make the Avatar to be not required but rather let's say the default value will be just empty string so so because some users will not have any avatars or the profile pictures right so let's make this optional with this question mark and now this is like a blueprint for how a user should look in our application it specifies that every user must have a username full name email and the profile picture or Avatar in this case that is optional and then we would like to create a user document let's say export interface um we could put I or we could just go with user document or let's just put it to be consistent and then it's going to extends okay it's going to extend the I user as well as the document that is coming from Mangus so let's just say document and then let's import the document from mongus and let's give a bit space then this is going to have the created ad which is the type of not string but date and then they update that and now this is an extension of user or for this I user and our user will have properties that are defined up here and it is also going to have some special properties that are managed by mongodb which are created at and updated at now we would like to pass it into our user schema so we could go ahead and create this um the I don't know like brackets and this is for generic types we could say user document or the I user document so here we are saying um to Mangus that you are defining a schema and this schema is specifically for documents that match the structure defined in I user document and then lastly we'll just go down here and we'll just say this user will be model and we need to import this from Mangus and it's going to have this user document and then here this model user document oops that should be bi okay this is what we have created right so this model I user document specifies that user is a mongus model and it follows the structure defined in this I user document interface and at the end of the day this ensures the type safety and autoc completions when we use the user model in other parts of our application so that was the typescript uh version of doing things and this just provides uh the type SA and better developer experience and also it just helps catching potential errors during development the only downside is like we have to just write a bit more code but it is definitely worth it in the long run now with that in mind we could save this and when we sign up we're going to use this user model and we're just going to create a user with this Fields such as the username uh the okay all of the fields that are coming from our GitHub account and for the authentication we're going to be using o JS so let's take a look at that if we visit OJs dode we are going to see that it is the new name for next o and let's get started with it we could go into the API reference and this is the version that we'll be using it is currently in the beta so next off and let's see the dos and while you're watching this tutorial this version might change so to install this please uh head over to this URL and try to get this command so I will copy this and back over to my project open up a new terminal and then just paste it and while it's been installed let's go into the docs and let's see how to use it so in ourv file we have to create this uh environment variables so the GitHub ID the GitHub secret as well as o URL and O secret so let's go and add all of them one by one inside our DMV and this has been completed we could close it so the first one let's just say oore URL and it'll be this value let's say HTTP Local Host and our Port API SL o and and we're going to get that what that means and then we would like to have our o GitHub ID and secret which we're going to get that in our GitHub account and lastly we're just going to have Oath secret and to create one secret we could go into our ter Al let's open up a new one and let's change the type to be git bash if you're using Windows so to get one we'll use this command open SSL Rand Bas 64 and 32 if you press enter it's going to give us this secret let's copy this this is autogenerated and we have to have it this secret is used to encrypt cookies and in production if you don't set it then you're going to get an error and now let's go ahead and try to get our GitHub ID and GitHub secret so here I am in my GitHub account I head over to the settings and then we're going to go into developer settings then we'll just try to create new uh app and here these are my uh past projects let's create just new one and our application name could be something like Snap next and I'll just say YouTube or maybe tutorial and for the homepage URL this can be our Local Host app and the description is optional you could put it or just skip it and for the authorization call back we could get our homepage URL then it's going to have the API o call back and then the provider name in our case it is GitHub so if you're using something like Google or Facebook or anything like that that should be that value in our case it is GitHub so let's register this application and then we're going to get this client ID I will copy this paste it into this GitHub ID and then we have to get a secret in here here we'll just say generate a new client secret and now we have this client secret we're just going to copy and head over to the EMV file and then just paste it now please use your owns and your mongodb as well because after the tutorial I'll just delete everything that you can see here and it's just not going to work if you try to use this one and with that in mind we could save this file and basically close this or let's just have it open and in the docs let's see what they say so the first thing that we need is to create this file of. TS and just copy this content and paste it into there so in our root we'll just say oath. TS and paste the content now we are using the GitHub provider so we would like to call that function and pass our client uh ID as well as the GitHub client secret so here we'll just call this and it's going to take an object let's say the client ID will be the process. EMV and it should be this name I'll copy and paste it then it's going to have the client secret again we'll just say oath GitHub secret it is this uh variable and then we had the secret that we created down here so after the providers array so we'll just go here and then put a comma and we'll just say the secret will be process. EMV oath secret that we have and then this is going to have a couple of callbacks so the first one will be the sign in so inside the callbacks let's just first save it and Shrink this so we're going to have a call back to sign in users and let's just say async sign in this is going to take a couple of uh parameters or arguments and let's have it the is going to be an object let's destructure the account and profile it takes a couple of more such as email or maybe user let's see okay but we'll just use the account and profile so this signin call back is executed when user signs in and we could check so let's say if account. provider is equal to GitHub if this is the case we'll try to sign in the user so let's say if this is the GitHub then we will try to First connect to our database and we have to create one function for this so inside the Library you could just say db. TS and create our function to be able to connect the mongodb so here let's say export const or maybe just async function connect to mongod DB and then we'll just have try catch inside the try will just say await mongus do connect to process EMV mongod B and now typescript says I don't know if this value is undefined or it's actually a string we could just say yes never going to be undefined it'll always be string or we could just say take this as a string so we'll just typ casting it and after this we could say console log DB or let's say connected to DB connected to mongod DB and in the catch we could basically just throw the error and maybe we'll just say console log and let's just uh console lock the error now this works fine but one optimization that we could do is to cat this connection so whenever we try to connect to mongodb we don't open up a new connection and for this we could create a cached connection and initially it is just going to be null and let's tell uh the typescript the type of this will be connection that is coming from Mangus or it'll just be null and that's how we use or with typescript and before we even try try to connect to database we'll just say if the cache connection exist then we'll just say return that cache connection and maybe we could console log something like using cached mongod DB connection and but if it is not cached then we'll just skip this go into the try catch we'll say const connection and assign this uh connection to this variable then we could do something like uh we'll just set this variable so cach connection will be connection. connection method or the property right so let's say connection okay we're going to get this and we could basically just console log something like new mongodb connection established okay so that was the optimization that we just added so we just cached it if there is a cache connection we return this we don't try to reconnect but if we don't have any connections we're going to first connect it and update our cache and lastly we will try to return the cach connection so this is our function to connect to mongodb now we could go into .ts and just try to sign our user in so if we are uh loging with GitHub then let's first try to connect to mongodb so await connect to mongodb and import that then we're just going to have a TR catch let's say now this function will try to either sign up the user or login the user so we could check for it with getting the user so let's say const user await use from the user uh model that we have here then find one with the email and how do we get this email it is from the profile and if you use profile that email this is that GitHub uh email of the user and we could say if there is is not user so we are signing up the user here then const let's create a new user with a user create method now this user will have the username email Avatar and the full name so let's say the username will be profile. login and this is the field that gives you the username from the GitHub and then we're going to say the email will be profile. email the Avatar or the let say full name just get the uh as it the name and then we'll just have the Avatar that'll be profile. Avatar URL but let's just put question mark so that we don't get this error from typescript and then once we create the new user let's save it into our database we'll just say await new user and just save it but if user is already existed so here let's just say sign up the user if not found but if we skip this if check then we'll just signing in and we'll just say return true now this indicates that was a successful sign in so let's say indicate successful sign in and in the catch which means there was a problem or error let's say console. logit and then we'll just return false and this will indicate the signin was failed and lastly if our account provider is not GitHub then we have to oops so after this if check we will just say return false and this will indicate signin was failed for non GitHub uh providers so let's accept this and save this file that is the file that we're just saying we're using the GitHub provider and this is our secret that we have and then here we have our callbacks currently we just have this sign in that gets the account and then the profile if our provider is GitHub we'll try to connect our database and then check if user is if user exists or not if we don't have that user we're just saving that into our database and returning true if there is no problem and this indicates that successful so the signing operation was successful and if there are some errors we'll just return false and user cannot sign in and after this file we have to create another file so let's save this and we're going to have oath. config.sys so let's go and create a export so let's say export const o config object that we're going to have it is going to have the pages and this will be let's say sign in it is going to take us to login page so when a user is not logged in or not authenticated we're going to take them to the login page they cannot visit our chat page or they cannot send any messages or anything like that and then we have to have the providers which is going to be an empty array so we could leave it like this because we already have defined our providers in oath. TS and we're going to skip this and then we're going to have the call bags again and this is going to be the authorized callback so let's say async authorized and then this is going to take two um values or parameters so oath and request we could give the type for this so the oath will be the type of session or it'll just be null if user is not authenticated and request could be type of next request okay that's going to be it and let's define our function body so here we could get the user so const user will oath. user now we're going to check if user is visiting the chat page so let's say const is visiting chat page so we could check this with request. next url. PATH name and if it starts with the chat and then we could have another variable to check if user is visiting the oath page so we could do the exact same thing or let's just duplicate this entire line and is visiting the oath page and we had two oath Pages if you remember the login and the sign up so let's say if this starts with login or if it is the sign up oops so let's just delete this copy this paste it and sign up now we could put our if checks so the first one will be if user is not logged in and they are trying to visit the chat page we'll just say no I'm sorry you cannot get there and then the other one is if user is authenticated and still tries to visit the login or sign up Pages we're going to just redirect them to the chat page so let's say if we have the user and they are trying to visit the oath page um then we could say something like return the user okay so we're just going to take them and redirect them to this URL which is chat and if none of this if checks uh if we haven't got into this if checks then we'll just return true and that means that we're allowing the user to proceed with the requested action let's quickly reiterate what this file is all about so this file defines the behavior related to user authorization and redirects here we have our sign in page if user is not authenticated we're going to just take it to the this path which is login and then we had one call back for authorization if user is trying trying to visit the chat page without being logged in we're going to take them to the login page and if they are authenticated and still tries to visit the oath Pages we're going to take them to the chat page and if none of this is the case we'll just return them to the page that they would like to go so that has been the o config.sys from nexo as well as our config that we have just created in this file and then we are going to add one extra configuration let's add it export cons config so we add this extra rule that is saying that the authentication should apply to most paths but not to the paths that include API the next static next image or it has a file extension of PNG and now in our application whenever a user wants to send a request or do some operation first this middleware TTS will run and it'll check if user is authenticated or not if not we're going to take them to this page but if they we're just going to continue what they are trying to do so that's the middleware as always that's just the function that runs before an operation and then the really last thing that we have let's say export default the next o call that function with o config and then just get the O property so in simple terms this file does something in behind the scenes and we don't need to truly understand it other than that we should know this file runs before a request that checks if user is authenticated or not and defines the configs and here we added this Rule and let me just paste a comment so we are checking if the authentication should apply to the to this paths or not and here we're excluding them so we could save and this is the file that you can get from the out JS documentation so if we leave everything like this it is not going to work because we're just uh missing one more important step that is going to be Rod handlers so first let's just talk about them what they are and then we're going to add for the authentication so inside the app folder we have to have a folder called API and let's take a look at the docs so we're going to go here and let's say route handlers oops so here we can see route handlers allow ow us to create custom request handlers for a given route using the request and response apis and that doesn't mean anything we'll just see that in an example but it is just good to know that Rod handlers are only available inside the app directory so inside app directory you create an API folder and then route. JS or TS file it is kind of like having page. uh JS file this is that special file and here we can see a convention let's cut copy this line and we're going to go under the app API and let's create the route. TS so we're going to go here API and let's just say um that should be a file route. TS and paste it if we visit this we're going to get let's return a response so return uh that should be next response. Json and let's just say hello world we could save and now to get this endpoint we're going to go into Local Host SL API and here we have it this is the value that we have now if you wanted to visit something like API user so for now we're going to get nothing right 404 but we could create that one so it works just like the pages so user and then inside we will have route. TS and let's just copy the exact same thing thing and then paste into here and you could just say user is here and if we try to visit this route and there we can see this is the response that we have now we're going to use this eight route handlers for uh next o so let's try to see the docs for this first so that you know what is that coming from so getting started login providers or Authentication um so here we have the pages but we are using the app router so we're going to change this a little bit so they say under the API oath create this rout which let's just copy this and then under the API we're going to have the oath and another folder we are going to paste it then we are going to create route. TS and that's how we use in app router we have to have this rout file so let's delete this user and this test one and what this does again some something behind the scenes this creates all the relevance of API routes within API oath in this wild card so that oath API request to all this end points and that means that this Library will just handle everything for us in the background the only thing we have to do is call this handlers so we had inside the oath there we can see we have this handlers object which is going to have the get and post method so inside this route we'll say import handlers and we could go into our alas so let's say PR at now we are in root and we'll just get from the O file and then let's say export const get method that should be uppercased and then the post from handlers and with that we have just completed the entire authentication setup that was a bit long so let's quickly reiterate and then we're going to try to implement this in our application so let's shrink everything and take a look at this .ts file so that was the file that we have created first and that has the GitHub provider with client ID and secret that we are getting from ourv file and then we had the O secret that has been used to encrypt the cookies so we passed it then we had the callbacks field that has the signin callback this will be executed when the user tries to sign in or sign up we check for this if the provider is GitHub then we're going to connect to database and save the user to DP if they are signing up for the first time but if they already have an account then we'll just try to return true that indicates that was a successful sign in and in the catch cases we'll just return false so that was our file and then we had to create this oath config to have redirects and here we are doing all of them with inside this callback and we have the default signin page to be this login route and then we had to create let's see the middleware that we have this extra config the rule and then we had to export this next off config that something happens behind the scenes and OJs does that for us and then we had the API folder oath and then all of our callbacks inside the r Handler so we had the guest and get and post method that we just exported and then in our application we'll be using two methods to sign in and sign out which we can grab them from here let's export them and save this file let's start with the signin function so the place that we'll be using this will be our o Pages the login and sign up Pages let's close everything and we're going to go into the sign up page if we remember that we have the signup page that contains the signup card so let's go into there we're going to see there is a form that holds the sign up button which is this one now normally what we would do is would be to something like this we would create an onclick event and then create a function let's say handle submit and then create this function prevent the default and then maybe send a request with fetch to our endpoint but now there is a different approach that has been introduced with app router so instead of on click events we use something called server actions and server actions are asynchronous functions that are executed on the server they can be used in server in client components and they are used to handle form submissions and data mutations in nextjs applications and again we will explain what server and client components are in a few minutes let's double check everything that we said let's go into the docs and search for Server actions here we can see they are asynchronous functions that are executed on the server they can be used in server and client components to handle form submissions and there are examples on how to using it so you create your server action in this case they call it as create but that could be anything really and then you put use server directive at the top that will indicate this code will run on the server and then you put your logic into here and now let's try to create our very first server action for this we're going to go into the signup card where we have this form and here we would like to add the action field and then just call our action in our case I would like to call mine as oath action so oath action copy the name and we would like to call This Server action and remember it was just a function that is executed on the server so async function and then oath action I don't want to take event as argument and then here just to make this work on the server we add the use server directive and then to sign up a user or login a user we have created this function that is called sign in so this is not only to sign in a sign a user in but also sign a user up right and that was the logic that we have added both for sign up and for login let's go ahead and try to call that function await sign in imported from the oath file and our provider is GitHub and that's the entire thing that we have to create let's save this file and see that in action by the way if we okay so we visit this page um the chat page we are going to get to the login page it is because we have added this all config that checks if user oops it is this this one if user is not authenticated and still tries to visit the chat page then we going to return false which indicates that was not successful and then it is going to take us to the signin page in our case it is log in that's why we are in the login page and now if we try to visit the sign up page you would like to just click that button and sign up our user and here we have if I click to that it is going to ask me that snap next tutorial application is created by this user and they would like to authorize you so let's authorize and we are being redirected to authoriz authorized application and here we have it so it took us to chat page it's because in the O config we said if user is authenticated and is in the O page just take them to the chat page now we are able to visit chat page but for now we don't have it and we are able to visit homepage as always but we can't visit the login or sign up page it is going to take us to the chat page that's what we set in this config file if user is authenticated and still tries to visit this old Pages which was the login or sign up just take them to this chat page and now we would like to see this logged in user and just change the content on the homepage depending on that so if we go here um that says start chatting and it is because let's visit the homepage okay that authentication was set to True by us and that was hardcoded now let's try to fix this and in order to implement this we're going to call a wait but just to call a wait we would like to make this async which indicates this is a server component and we're going to get there again a couple of seconds uh or minutes and we would like to get this authenticated user by this oath object so here I'll say give me the oath that is coming from oath file and then call it now we are going to say let's say this is session and console log the session and if we save this file let's see if we visit homepage just refresh and that's the user that we have this is the uh name that is coming from GitHub that's the test GitHub account that I have created the email and then the image that we have now instead of saying true um let's say if there is not session then show this button that says log to explore but if user is authenticated then show this button that says start chatting and since this part I mean since we are logged in there is a session this part will run and we see this start chatting button now let's try to add the log out functionality that was inside the top bar let's go there inside the nav bar uh we could shrink our um to the terminal and here we have another form and let's call this um the action but before that I would like to make this form into its own component or this log out button into its own component so that if you would like to use this uh log out button in other parts of application you could do that so here I'll say log out button. TSX and I will call it log out button and then paste this form import the button and then the log out icon now let's save to get this formatting and import the log out button okay we could close this and delete this icon we're not using it and inside the log out button now we'll do the exact same thing we're going to have an action let's say um log out action then we have to create this function async function which is a server action so so log out action that is going to use the use server directive and then call the sign out function that is coming from again from this file right that was the sign out uh function so we are going to go inside here and let's just save this give a formatting and then inside this page um we could save this again let's go now here and test it out if I click to this button there we can see now we are logged out and it says log to Explorer if I click to that it's going to take me to the login page and if I go to chat page that will take me to the login page now let's quickly try to add this login functionality and then we're going to talk about what server and client actions are so I will go into the login card let's first close these and then we had the login login card which was called inside the login page and we had the form now I will say action and then instead of doing the exact same thing or let's just do it so I'll call it as oath action and create it and then we're just going to take this into its own file so async all function then we would like to call the US server directive as well as the sign in functionality or the function in our case and if we save that should work the exact same way um and also let's try to check our database so we sign up the user but we didn't check it if we go uh into our application or the database in our case um and then click to here browse collections then you're going to see that we have the users's collection and that was the user that we have created a couple of minutes ago but now if I try to log in with this user it is not going to create this again and that was the code that we have written inside this file right if we have the user now we are always is going to skip this if check and just return true and that means we'll just log in the user let's click to this log in with GitHub it's going to take a bit time but hopefully it should take us to there and now it just redirect us to the chat page now we can um move on or continue we were in the login cart um okay so we have created the exact same action in two files now this is what we call the inline server action you just call call it inside uh in the exact same file with the form and there is another way where you just put it into its own file so inside the lab let's create a file called actions. TS and we could take this function I will copy this and then paste it to here now and let's import this as well now here we imagine if we had a couple of more different actions so one more one more one more all of them are different do we have to put this Ed server into all of them well not really we could delete all of it and then just put a use server at the very top of our file so use server will goes here and then I mean it'll go here and now we don't need to pass this directive into our each action and in our case we have this oath action and let's say export this now we could save this file and I will I mean I'll just comment this out so that you have this as reference and then we are going to try to import this one from here okay we could delete this and then inside our login card we'll do the exact same thing so let me just say this was an inline server action delete this one and then import this from the actions and let's save this file now there is one more problem and we're going to solve this in a couple of minutes so the problem is when we try to log in it doesn't show us any loading spinner or indicator and we would like to fix it but before that let's talk about the server and client components so there are two environments where web applications can be rendered the client and the server let's try to quickly remember them the client refers to the browser that sends a request to a server and then displays the response back and then the server is a computer that stores your application code it receives requests from a client and then sends back an appropriate response and that takes us to the server components and client components let's start with the server components so they allow you to write UI that can be rendered and optionally cached on the server and there are three different server rendering strategies the first one is static rendering and this is the default default one and this is what we have been doing so far and then there is dynamic rendering as well as streaming and we're going to be using these two as well later in the course but if we have to summarize them in one sentence the static rendering routes are rendered at build time or in the background after data revalidation and again we'll see what data revalidation is when we start to working with our data and then there is dynamic rendering and here routes are rendered for each user at request time not on the build time and then there is streaming and this enables you to progressively render UI from the server let's say we have a blog page that you'd like to visit and there are some Dynamic data that'll be served from the server and there are some static data such as or static components such as sidebar and maybe navbar we don't have to wait entire page to load to be able to interact with the page so so we immediately render the sidebar and then top bar and then we put some loading skeletons for this data that will be served from the server so just like they say in the docs partial content with loading State and this is that data suspended content streaming in and here are some benefits of server rendering maybe you should pause the video here and read all of them one by one that'll take maybe one 2 minutes and this is pretty self-explanatory and then we have the client components and they allow you to write interactive UI that can be rendered on the client at request time and when you want to use a client component you have to explicitly decide or you should Define that is this is a client component and we will see some examples just in a second and here are the benefits of client rendering so the interactivity when you want to use things like use State effects and event listeners in this case you have to use the client rendering and then you would like to use some browser apis such as geolocation local storage then you'll be using client rendering and to be able to use a client component you would just put use client at the top so what we have done so far uh we never said use server or use client it's because by default everything is server components now this is a server component this page is a server component this layout is a server component unless you come to the first line and say use client now this will make this a client component but if you don't put it it'll be Ser component by default and in Ser components you can use the async keyword and you can fetch some data inside so before the returning to jsx you will be able to use a weight and maybe fight some data and I think that's what we did in the homepage you visit here we have this is the async server component and we are call calling this oath function by aing the result so let's delete this save this one and save this and the example that they give in the docs is that they have a use state so they have to use the use client directive at the top and when you click the button it increments it increments the count by one and there are two rendering strategies for client components the full page load as well as the subsequent navigations now on the full page load the client component does not completely rendered on the client but instead nextjs will render a static HTML preview on the server and this means when the user first visits your application they will see the content of the page immediately and then on the background it's going to hydrate and what that means it is going to add the code that the browser needs to have that interactivity but on the subsequent navigations client components are rendered entirely on the client without the server rendered HTML and I hope that made sense now we have seen the benefits of it but now you might be wondering when to use which one so they give us a nice table that we can visualize so when you want to fetch data or you want to access backend resources you want to keep sensitive information on the server such as access tokens API Keys Etc and then you want to keep large dependencies on the server and you want to reduce the client side JavaScript then you can use server components but if you need interactivity or browser only apis such as local storage geolocation and that kind of thing you would use client components and lastly if you'll be using react class components then you have to use client components as well so this has been server components client components and server site rendering as well as client site rendering now let's move on with our application so we had this problem when we click to login with GitHub button it doesn't show us any loading spinner or any indicator and we'll like to add this and for this we are going to go into first let's just close everything and then login card and that's the place we like to add it now in our login page we set that so we said everything was server component by default and this is a server component as well but now we would like to make this login card to be client component and it is because we would like to have some state to show some loading spinner and or maybe some loading indicator and whenever we need State we would like to have a client component so let's add our directive which was use client and that will indicate now this is a client component and if I want to have a pending state with server actions I could come here and I use a hook called use form status and call it this is coming from react D and this this is going to give me let's say the pending State and I will say this button should be disabled if pending is true so I'll just pass the pending and if we save hopefully that should work we're going to go here um into homepage first we need to log out so I will quickly log out and then go to the login page and let's try to see this I will click to that and here we have it this looks like disabled and I cannot click to that again and there is something important here to understand if you're are using this used client directive that means this is a client component okay we understand this but if you have this directive you can't use inline server actions so if it were something like this okay so just delete this import this is not going to work even if we import this one you cannot use inlines server actions inside a client component if we save and that should break okay it says it is not allowed to Define inline new server inside a client component that is something to keep in mind now I will just undo everything that I did up until here I guess okay that should be pending and I will just save this file but now what happens if we have some errors we didn't handle any of those so instead of using action just like this we would change this a little bit so we use use form state if I can type okay we would call this use form State and it's going to take two arguments the dispatch in our case it is login or I mean sorry it is the oath action and then it is going to take the initial State I will just put an empty string and on the left hand side we are going to get two values the error message and then the dispatch now instead of of having this action as oath action we're going to put the dispatch here and it's going to be this function and then for the error message we could put something like after the sign up link so here we'll just say if there is this error message then display this ptag with this text Rat class and show the error but if there is not error message then just return null and we have a typescript error that we will fix in a second then we would like to go into this both action and let's try to return something went wrong if we save this file and then this one let's try to log in again so first we'll log out and then we try to log in now here something went wrong it's because this function returned an error right that's the thing that we have grab it and then we just show that and render it in our UI but now now what happens if we don't return a string but instead if we say Throw new error now imagine something went wrong in this function at and it throws some errors so let's say some weird error and let's try to see this in action we're going to go again to the login page and if we click to that it is going to crash our application and it's going to say some weird error and to fix this we have something called error. JS so let's search for it and this is a file that defines an error UI boundary for a route segment and in our case we would like to see this in our o segments so the login and sign up Pages we're going to go here and create this special file since we are using typescript we are going to say error. TSX and I will provide you this file you can grab it from the repo and then just paste this and here there are even some notes so this must be a client component that's why we add this directive and then it takes two arguments the error and the reset and this error is javascript's native error object and then the reset is a function to reset the error boundary when executed the function will try to render the rod segment and here we show the error and we prefix it with something went wrong as well as a try again button that calls the reset function so so we could save this and here also we have the typescript uh types so yeah let's go ahead and test it out if I click to this it's going to throw that error and it'll be catched by this error. TSX file now if I click to this try again it's going to again take me to the login page if I click that again something went wrong and then that error that we throw and there are still some weird edge cases that you should be aware of so I will delete this through new error and since this is an async function generally you would like to use TR catch and then in the try you would like to sign in the user and then in the catch you would grab the error let's say type of it is any and then you would here say return message I mean error. message but if you do it like this then this will still throw an error even if the signin was successful so let's see that in action we're going to try to log in and we see this error of next redirect and it is because when we sign in successfully this will call the redirect function from nextjs and if you take a look at that from the dox you're going to see that um okay we're going to click to this so the redirect functions allow you to redirect user to another URL okay that's nice but the thing is redirect internally throws an error so to fix fix this we're going to go into the catch block and we're going to check for that error so if error. message is equal to next redirect then we're going to throw the error but if this is not the case if this is a different error then we'll just return error. message so that we'll be able to catch it and see it here so we're going to save and hopefully that should work fine now we're going to go here refresh and then log in with GitHub it takes a bit time but hopefully we should be logged in and there we have it so the problem was when this is successful it's going to call the redirect function and this internally and by default throws an error so we catch it and without this we had we had this return and that showed that next redirect error in that P tag but we added this when we got this redirect error that means we just going to throw that error so it is not going to affect our application okay so I will save this file and also I would like to go inside the log out button and then get this function or this action into this actions file as well so I will cut it paste it and Export this one and then I can import it I don't have to put this use server directive I already put it at the top so yeah that's going to be it let's go here and and then import this one now let's try to add that form State and form status into our signup card as well so instead of calling this o action we'll call that use form state that is going to take this action as well as the initial state that could be an empty string then we're going to get two values the error state or message and then the dispatch dispatch function we are going to put this into action and we're going to have the pending state so const get the pending from use form status and we're going to say this button um disabled if it is pending and just to have accessibility so we could add area disabled and then put the pending as well so we could copy this and then paste it into our login card and to the button as well and to have the error message we're going to copy this save this file and then paste it to here if we have an error message then we're going to just show it inside this ptag and we could save this file if you wanted to you could add this exact same thing to the log out button but I will skip it so that we don't waste any time but again you would just uh take this button into its own component get the pending State have a use form State just like this you get the dispatch the error message if there is any and then you would pass this action in our case that would be log out action and with this that's going to be the end of this section now we know the error file how to use form State the form status how to use server actions what server components are what client components are and how to use them when to use them and the next thing that we'll do is to add the chat page and I just noticed we have forgot to add this use client directive at the top so that we will be able to use hooks in our client component so let's save it and I'll see you in the next section okay so this is going to be the design for our chat page that we're going to have at the end of the section on the left hand side we can see our sidebar and on the right hand side we can see this user this beautiful background image as well as this camera and when we click to the camera we can select an image from our machine let's go with this one and that is going to open up a dialog so that we can preview the image if we wanted to we can change this one so let's change it and then we're able to go to the next step where we're going to have this recent users and we could go to the preview step and maybe just cancel this process so now let's try to build this this is where we left our app now we would like to create a chat page and of course that's going to be under the app folder and then we're going to have a page. TSX file under the chat folder and here we are not trying to learn any CSS our focus is to learn um njs Concepts for that reason in this section we're going to be mostly copying and pasting code and there is not going to be any logic but rather than styling and I will still try to explain every single step that we do so here I will just paste some code and uncomment this and in case later in the course if we change anything in this file here I'll give you this starter one that I said before so I'll say starter code for this file oops that should be file and I will put the timestamp where we paste this in the video okay so at the end of this course I will update this and then here we're using chat camera component let's go and try to create this it's going to be under the chat uh is going to be under the components and chat folder so components we're going to have chat folder and then chat Das camera. TSX and before we even try to add this page we would like to have a layout in the chat page so let's say I mean uh layout for the chat folder so we'll say layout. TSX and the reason that we're adding this is going to be the sidebar that we're going to have in all the chat pages so I will again copy and paste it I think it is about 10 lines of code and just open this up so here we need to create a sidebar that will be in all the chat Pages later in the course first we're going to have Dynamic Pages for chat so we we will always have the chat sidebar that's why we're adding the layout that was the shared UI now let's try to create this chat sidebar under the components again so here we're going to go and say chat Das sidebar. TSX so here again I will paste this and then comment this uncomment this and then at the end of this file I will paste it again so that will be the starter code and that's going to be the starter code for this file and again we will put the time stamp at the end of this video and then here we are using avatar from chat Cen let's see how can we import this so in the the documentation of shaten we can search for Avatar and here we can see we just need to copy this and then paste it into our application and here we're going to go and try to paste this I will paste it and that's going to install it and put it under this UI folder it's going to create an avatar. TSX okay it's been installed and we have this avatar. TSX now we can save this file and save the layout and here we need to create this chat camera component I will paste this and uncomment this and then once more that will be the starter file so let me just go and say starter code for this file so that you can copy it from this file in the repo and then paste it and move on with the course so we are going to save this but before we need to create a couple of more components for now let's just delete this or uncomment this so that we can see the result we could uncomment this as well as this one and let's say comment this one maybe just this part okay and let's try to save this and see the end result now if we go to the chat page we are going to see that we have a sidebar as well as this right hand side so how does this work let's take a look so here we have the chat camera on the left because this is a flex container and then on the right we have this image which is snap emoji.png which is this one and then we have the background image I think that is coming from the layout file if I'm not wrong okay I am wrong that should be in okay it is this background chat that we have added in the Tailwind config okay so it is this one in Tailwind config TTS and we have added this at the beginning of the tutorial and then we have created this layout. TSX file that will put the chat sidebar component to every page that we that we create later in the course in this chat folder so whatever page we have here we're going to always have the chat sidebar on the left and then we're going to have the page content so just like here and then in the chat camera component we have commented a couple of things now let's try to add them one by one so here we're going to have this read file as data URL from the utils file let's go ahead and try to add it so I will paste this and here we have a comment so this function allows you to easily convert file contents to be displayed as an image so what you do is you select an image file from your machine and you pass it into this function and then it tries to read that file and converts it as this data URL so that you can display this as an image in your web browser and we're going to see this in action in a couple of seconds now let's save this file and you can get this function in St overflow or chat gbt it's because this is pretty common and you don't need to truly understand this but it's pretty basic I would suggest you go in depth and just try to understand this it returns in promise and read the file then just convert it into this data URL which is base 64 and then here we need to um so let's uncomment this and then we would like to get this image preview dialogue component as well as select user dialogue so that is going to be shown um up here or down here so let's see um okay so so where I showed you we had the first step that you selected image and then you press that next button and then you see the user to select and let's try to create them one by one the first one will be image preview dialogue so we're going to create it here image preview dialogue TSX so I am going to paste this and then I will paste it again and uncomment this this is going to be that starter file okay the starter code for this file and again the time step sample goes here so here we are using a different component from chat CN let's try to install it that's going to be dialog and so let's search for it that's going to be dialogue and this is just a model and they rename it as dialog so you could copy them and paste it into your application and just style it however you wanted to so I will copy this and you should do to and then we're going to go into our terminal and then paste that is going to create this dialogue file under the UI and that is done now we could shrink this and save this file then we're going to just import the image preview dialogue that we already have and then we need to create this select user dialogue as well so I will create that select user dialogue. TSX and then I will paste the code and then once more and again this is going to be that starter code and here we're going to have the time stamp now let uncomment this and hopefully that should work okay we have two more files that we need to create the first one will be let's say this user card that should be inside the chat folder so user- card. TSX and then we had another file called chat SVG that is going to be under the svg's comp uh I mean folder so inside the components svgs and then chat SVG ttsx and I'll just paste the file content you can grab this from G preper as well we're not going to change this at all so here we have four different svgs that are in the format of react component that takes props as an argument so that we can change some class names and here we have type that is typescript specific that says the props will be SVG props so that we can get this formatting so I mean autocomplete so we'll say props Dot and here we have everything that you can imagine with this type of prop so let's delete this and save this file we can close this then here we need to create the user card and we'll just paste the content so I will paste this twice and the second one again will be that starter code and I'll put the Tim stamp that's getting a bit repetitive but I just had to say this so that you don't miss it and then we're going to uncomment this and if we save now everything should work fine we're going to save this and so let's preview the end result and then we're going to go ahead and try to explain each file one by one so we have already seen this now what we have added was this uh dialogues now let's select an image so here we have the image with the change button and the next button if we click that we're going to go to the next page where we can see this chat and we can go to the previous one if we wanted to we can change the image and then that's going to update the UI and then then again we can go to the next one and just cancel the process so now let's try to explain how this works step by step I will close everything and let's explain uh we have added 10 different files so let's go one by one we have the page for the chat page and then the layout the layout was the shared UI so we have put the chat sidebar that is going to be in every chat page so this is everything this file does and then we had the chat page where we have chat camera component and then the this image so the chat camera component as well as this image now let's take a look at the chat camera this is where the magic happens so this is a client component because we are using States and interactive things now here we have an image that is this camera image and then here we have an input that is type of file that accepts images but it is hidden you cannot see that and what happens is this has a ref that is image ref that we have created with use ref so when you click to this div it is going to trigger this click event on this image W so this file explorer will open when you click to this image and then when you select an image this handle file change will run and that's going to check if you have selected an image and then it's going to send that file to this function and that will convert that file in a format that can be displayed as a image and then the result that we get we put this to the selected file state and here again we have some type script type that we say this event will be type of this react change event from an HTML input element so that we can get this let's say autoc completes so event Dot and here you can see there's a lot of things so event dot Target it was in our case now if you put that you're still going to get pretty much um so a lot of different aut completes so Target dot files dot maybe size or length I'm sorry so this is the beauty of typescript if you didn't put this so let's say we don't have type for this then we not going to get any auto completes there we have so that's so let's just put them as it was and then we have this two different components the image preview dialogue as well as the select user dialogue and here if this step is the first one then we're going to show this one and when we click to the next button that is inside the image preview the step will increment by one and we're going to see the user dialogue so let's preview what that means so when we select an image we are in the first step and when we clict to this next button it's going to increment that step and now we are in this dialogue and how that happens is that we sent this props to image preview dialogue let's open that up okay the props that we sent is selected file the on close function and then on image change as well as set step now let's see how that look like so here we have this component and and that's how we add types to a component so we created an interface that says this this component will take props that is selected file and the type of this will be either string or maybe undefined and then the onclose function we have that is going to return nothing and on image change function as well as the set step function that is react set action and that takes number as an argument so we destructure all of this and here we have this dialogue that is coming from shaten and we check if this is open or not so if this is open then we're going to see the content and we're going to determine if there is a selected file if there is then this dialogue will be open and if there is a selected file then we're going to show this image that we get as a prop and then let's see we have the on close function we call this when we uh interact outside as well as on image change so this is that button that says change the image when you click to that this on image change function runs and then we have this on click function that increments this step when you click to that next button and that's pretty much this file so if you want to explore this just please pause the video and try to read that 10 different files that we have added and that shouldn't take more than 5 to 10 minutes so I didn't want to write all this CSS classes this components because there is no logic here nothing complex going on we just have one logic that is incrementing this step and depending on that step number we're just changing the um dialogue so it's either image preview or the select user and then one more thing that we have added was this utils file that has this function and this is pretty po popular on the internet that you can pretty much copy this from anywhere and that converts your file to be displayed like an image and there is one more thing that we would like to add so in the select user dialogue if we just duplicate this maybe 20 times there is going to be something that looks ugly so let's select an image first so if we select an image we go to the next step we have this ugly scroll bar and to fix this we can go into the global. CSS and just paste this and what this say it gives us nice looking thin dark mode scroll bar so let's save this file and if you visit that chat page so here we can see this looks a lot better than previous state and here I would like to mention one more thing so in the chat camera since this is a client component any component that you put into this file so the image preview dialogue or this select user dialogue they are also um a client component so we don't need to put would use client at the top here so we don't need this directive because its parent is already a client component that we can see here and the same goes to this one and also I just want to quickly mention what is going on on this line why do we have two exclamation points before this selected file what happens if we delete them so when we delete them we're going to get an error from typescript that says hey this open wants you to have a volume value or under defined value but what you passed is selected file that is the type of string or undefined can you convert a string to be a bullion so that I don't give any errors and the question is how can we make a string value to be a bullion value so here let's take a look at the JavaScript console and if we paste some string value and if we just uh check if this is equal to a false value and it's going to say no it is not a falsy value value so that means this is kind of like a true value but how can we make this a bullan so that this gives us true so if we just paste this and we can go and negate this so now this is a bullan that says false but hey this is not a falsy value can we make this true so we'll just negate this once more and there we have it now when we pass this selected file so let's say we have this URL oops so let's say selected file is this URL and then if we just put this to exclamation points now this is going to be a true value and the open will be true so that we can see the dialogue but what happens if we have an empty string and now if we just ask is this true is this a true the value we it's going to say hey no this is not true and that means this equals to false but how can we convert this string to be false so let's just put that and and if you put so if you just negate this then it's going to say true but hey that was a falsy value right so if you just negate this once more then here we have it we converted an empty string to be the buan version of it and that's the reason why we did this so when we put both of them these two exclamation points or we call them as bang operator we're not going to get any errors now typescript thinks this is a buum value and indeed it is we just convert it a string value to be that Boolean value so here let's just delete this one and please take this as a note so that you can use it in your upcoming projects and now let's save this file and there is one more thing that I just quickly want to mention so let's put image preview on onto the right hand side and then here we have this user dialogue so let's shrink this and then here if you have realized we are using props with type and then we here we are defining props with interface and pretty much they are the exact same thing with just some uh syntax difference here we have to put this equal sign and then just put our props and here you just immediately open up Cur braces without eal sign and then the other difference is um here we have the react functional component so we say this image preview dialogue will be a functional component with this props and here we instead we don't do that but we just uh pass it after the props so we put a column and then the props so if we just let's take a look one by one so here we say um just put them after the props and the other usage is we say this is going to be a functional component and here is my props but instead of doing this you could still just delete this and then put it after this um destructuring the props so I could copy this and then now paste it it's the exact same thing I just wanted to add two different versions so that you would be familiar with with two usages and in other projects if you see them so you don't get confused so yeah that was the types and interfaces now in select user dialogue we have added all of this we could just delete them and keep only one and then there is one more thing that I want to change so here we have this close icon that is coming from dialogue um I will go into that file it was inside the UI open up the dialogue and where use this x so contrl D2 find it oops or let's see where that is okay it is in this one and I just want to uh I mean comment this so that I don't see that close button and again this is the beauty of shat Cen that's why it shines the quote is yours you can just change it immediately and whenever you want it to so let's go here now we don't see that close button and also in the last section we have added this chat sidebar that I forgot to mention so we have the lot button that we're importing from shared where we built this in the previous sections and now this is just a reusable component and the only thing that we have to do to log out from our account we just import it in any component that we would like to have and this chat sidebar is a client component I mean I'm sorry this is a server component and we can use async with it and here we are trying to extract our session from the oath function so yeah that was the server component and and then the chat camera was the client component so in one page you can have server components and client components and of course that was the design part so we don't see this users on our sidebar but we will do once we get to there and once we interact with our database so we're going to create chats and users and then we'll display them here and to be able to do that we need to First design our database which is going to be our next section okay so this is going to be the structure of our database we're going to have one table called chats and another table called messages in the chats table we're going to have an ID field for the chat ID and then the participants array that will hold the ID of the users and then the messages array is going to hold the ID of the messages and then inside the messages table again we're going to have underscore ID field for each message and then each message is going to have the sender and receiver fields that is going to hold the ID of the sender and then ID of the uh receiver user and then it's going to have the content so the type will be string so that will be either something like hey how's it going or a URL value so it'll be URL value if this is an image so let's say we're going to store our image in some place and we're going to get the URL of it and just put it into this content and then we're going to have the message type it's either going to be text or it's going to be image and then the open fields which is Boolean so true or false now let's try to create these models in our code base so we have added one model called user model in the previous sections and we have explained every single thing in this file one by one if you want to remember that you could check out that um section maybe it has 5 to 10 minutes and then come back to this one now we're going to create two more models so the first one will be chap model. TS so let's try to add this so first uh let's create this schema so const schema new mango. schema and that's going to take an object and let's close it and then let's import the mongus and the fields that I that we set will be participants and the messages so here we'll just say participants and here we have an autoc complete let's accept that so it's going to be an array and each value will be type of object ID that references to the user user model so basically this means the participants array will hold ID of users and then we're going to have the messages so let's say messages array and it's going to be actually the kind of same thing so it's going to take an object with the type being this ID and then reference will be to the message model that we will create in a second and then at the end of this object we could put a comma and then open up another one so it will say time stamps should be through and that will give us the created ad and updated ad Fields now let's try to create our models I mean interfaces and that shouldn't be a schema but let's say um so [Music] chat schema okay so we're going to create our interface let's say export interface I chat and then here this is going to have the participants so let's say participants and that's going to hold let's say types Dot object ID and that's going to be an array so we could import this types from Mangus and then we're going to have the exact same thing for messages and then we would create something let's say export interface the another interface that will be chat document or I chat document that's what we have done in the user model as well that extends the I chat as well as let's say the document that is going to be coming from mongus and this is going to hold the created that and updated that fields and here we can pass our chat document so I chat document so this is that generic type and then at the end of this we'll just try to create it so const chat model and that's going to be a model that is coming from oops that should be model and then we're going to pass this I chat document and instead of immediately creating it let's first check if this is existed so Mangus models. chat so we could put a question mark to here and then if if there isn't then just try to create this one on the right hand side and lastly we'll just say export default D chat so that's going to be it for this file let's save it and we're going to create the message model so message model dots so here let's start with the interface we'll say export interface and we're exporting this in case we we use in our code and actually we're going to be using them a lot so we'll be using this chat document later in our uh later in the course and then for user uh document we'll be using this interface that's why we are exporting them so with that in mind let's close them and just try to add them one by one so we're going to have the sender that will be the types. object ID let's get the types from Mangus and then we said that we're going to have the receiver that is also going to be an ID and then we're going to have the content that will be type of string and then we're going to have the message type that will either be text or it is going to be oops image so just like this and then we're going to have the open field and that will be bullion now let's create the message document so export interface iMessage document that extends iMessage as well as the document and let's close this and import the document from Mangus now inside we're going to add the create that and update that Fields now let's create our message schema so const message schema we're going to just Auto accept that and and open up an object let's import the mongus and we could I think also do it something like this and we had to just import this schema and so that's just exact same thing we could delete delete Mangus now and then here we're going to add all these fields one by one so we're going to have the sender that is going to be type of object ID reference to the user model and that sender ID should be required let's say and and then we're going to have the exact same thing so I'll just duplicate this but I will change this to be receiver okay so we're going to have the content so if we put it something like this control space we can get this Auto completes from typescript so content will be type of string and of course that should be required and then we're going to have the message type that is going to be type of string and require true and we could even extend this by saying this will be type of enum so it's going to be either text or image and lastly we're going to have open field type of bullan um so by default let's say it's going to be false we could delete the required so when you just create a message so when you send the message the default will be false and when the user opens that we could uh manipulate this field and just make it to be true and then again at the end of this file we're going to create our model so let's say message that is going to be a model with imessage document and I'll just aut to accept this let's import the model from Mangus and then let's even get the mongus okay it's going to check if this model existed or not and if not it's going to try to create it with this schema and then we'll just say export default D message and that's going to be it for our models so we could save this file now so now we don't have any users in our database let's let's try to create some we're going to go into mongodb or Atlas and we're going to click to this database then browse collections then here we should see our users um collection and then this is the only user that we have so how can we um duplicate this so we're going to clone document this is going to give us a different ID but it's going to have the same username full name e email and Avatar so here we can see the content now I would like to change this so I'll say username will be jandoo and we're going to give a full name and full name will be jandoo as well as the email will be jando gmail.com and Avatar could be same so I will just insert it now and there we go so I'll do the exact same thing a couple of more times and you should do too so that we have at least four or five different users and then we will continue with the course okay so I have added a couple of more different users into our database and in total now we have six users now the next thing that we would like to add will be this um users that would like to show in our sidebar so here I have a screenshot so we would like to fetch users but not only their profile uh information but also the last message so here we can see the last message sent by us and this is that date that we sent the message and the message is not opened so here we can see also uh with the Jennifer we don't have any chat history so it says say hi now we want to also fetch this latest message data and that's what we'll be doing so for this we're going to go into our code base and under the lib we can create a file let's say data. TS and that's going to uh contain our files to fetch data so let's say export const get users for or sidebar and that's going to be an async function and as an argument it's going to take let's say the authenticated users ID okay authenticated user ID and that's going to be type of string and you will see why we're taking this because we're going to be using it and inside now let's have a try catch and type it one by one okay so it's weird okay we forgot this Arrow okay okay so we're going to first let's say wait user model that find every user but unless so not equal the off user ID so we're going to get this from model so we have the user model we are trying to find every single user in our database but not the authenticated user ID and that's how we do it we say the where the ID field is not equal to this o user ID and this is going to give us so let's say const all users and each user will be let's say a user document and array of them right array of user documents so we could say I user document and import import it from our models so here we have and then we would like to fetch the user info so let's say const users info and that's going to be a and that's going to be something like this let's say await promise that all so that they run in parallel and we will say all users map get each user that will be in asynchronous call back and for each user as we said before we would we are trying to get the last message if there is any so we'll say con last message that is going to be type of IM message document did we create this one let's see inside the okay if we just okay that should be actually something like this so first we put colum and import it and then say equal and that might be null value as well right oops so I accidentally opened the new file okay so we're going to try to find the last message that can be type of iMessage document or if there is there isn't any last message then type will be null and then here we're going to write our query so so await message. findind one so here let's close this and then close this One Import the message model from our um so from this file message model so here we're going to have a query that is um so dollar sign or and that's going to be an array so let's say where the sender is equal to user doore ID or it is the receiver will be user doore so this basically says find the message that is sent by this user or received by this user and that's how you uh write it in and then we would like to sort this and we'll say sort where the created ad will be minus one and that will give us the latest message and we're going to take that latest message and we just put it into here uh and that will say okay it is sent or maybe it is received by this user and so on and so forth but now if we remember in our let's see so each message document just contains the ID of user right it doesn't give you the full name or the profile picture or username it just has the IDE of sender and ID of receiver it is just reference so how can I get the profile picture of this user or let's say full name of this sender and for this we have a populate uh function in mongus and here we have an example let me just zoom out a little bit so here we have two users with ID 12 and 15 so this user sends a message to this one and the ID of that message is 99 if you say message. findind the message with ID 99 so let's say this is that message the sender ID is 12 the receiver ID 15 this is the message content uh message type and opened now we know it is sent by the ID that has 12 um user ID but we don't know the Avatar of this user or full name username and how can we solve this so we're going to call the populate method so we are going to take it in chain here so message. find ID with 99 and populate the username and full name of the sender now instead of getting this document we are going to get this document okay if we just take it to here so previously only with this okay only with this part we just get the IDE of the sender but now we are getting it as an object where we have the username and full name so that we can and let's say we have Avatar and we will be able to get the Avatar and just put it into here and then we can also put the full name so this is the point of using this populate method and this is what will be doing in our code I hope it made sense so basically instead of returning just a reference you say hey give me these fields for this path which is cender that will give you and we could even double this again so let's say I will change this and I'll say give me also the receiver username and full name Avatar of the receiver now instead of getting this as number we are going to also get this as an object I hope hope that made sense now let's try to uh write our code so after we sort we're going to say populate and I'll just go here I'll say populate the sender and the fields that I would like you to populate will be full name Avatar as well as let's say underscore ID then you would like to populate the receiver as well so the full name Avatar as well asore ID and then let's just execute this quer and now that we have the last message so let's try to return an object for each user so we're going to have the underscore ID that is user ID so we don't want to take this so we're going to have the participants and in this participants array we can put the user itself only so we we don't really want to put ourselves which is the authenticated user because on the left hand side when we render these chats we will only get the information of the user that would like the chat that's why we only put them into this array and when we use this you're going to understand that uh better so here let's put a comma and lastly we will have a last message field so let's say if there is last message then return this object else just return return null so inside this object we're going to have let's say get all the fields of last message and convert this to be a Json and then this object will have the sender so let's say last message. sender and then it's going to have the receiver and again last message. receiver and these are going to be the fields that we have just populated so at the end of this we will just say return users info and we could save this file and let's just try to explain what we what we have done so we just try to fetch all users that we have have in our database but except the user that is authenticated so let's say it is Us in this case we're going to get every single user so here but not ourselves so that we don't see here ourselves and we and we don't send message to ourselves that's the idea and then for each user we don't really want to only get the profile picture or the full name but we also want to get the latest message so if there is any we're going to show something like this was the textt message that we have sent and this is the date that we that we sent the message but if we don't have any last message so we don't have any chat history with this user and this user so we just show something like say hi so here that's what we are trying to do we are trying to get the user info where we have the last message and then we have explained this populate method we are populating these fields for both sender and and receiver and once we done this we return an object with this Fields so in the participants we just put the user and not the authenticated User it's because here we are only going to see the user that we are chatting with and then we just put the last message field and lastly we just wanted to return that user info and in the catch let's just say if there's any error just throw the new error with this error. message or maybe just throw the error and we could put something like console log okay with this this function is completed now and we are able to use this so let's save this file and let's try to call this hey guys a quick pause here I am recording this after I completed the tutorial so here there's only one thing that we are missing in this case this uh line should be fixed now please just pause the video here and try to fix that line with this one I updated this in the repo that will be the latest commit I think and here you need to just update it with this or logic so here we just say find a message that is between uh these two users and here is the case so this sender could be this user and receiver will be authenticated user or the sender will be authenticated user and receiver will will be this user and that will give us the correct output if you do it like this then later uh after the deployment you won't have any weird uh scenarios so sorry about that I missed it while recording but I just realized so here is the fix try to just fix the fix those four lines and now let's continue with the course so since we're going to be using this function in our sidebar let's go into the components and chat chat sidebar so at the end of this uh file where we're going to have let's say before the aside and below the St we're going to put a component called chats and we need to create this so again here I will just have chats. TSX and here we get our boiler plate as well as some let's just try to actually add some markup so here let's rename this to be chats and then this is going to be a Navar so we will say it's going to have class name of flx one overflow y Auto and then inside the nav we're going to have a URL and here we're going to get chats so we actually want to fetch the and just call that function and fetch the chats so before that we need to get our session so let's say session from o call the function from o file and to be able to use a weight we're going to mark this as async it's because this is a server component and we are able to use the async but if it was client we couldn't use it and then we're going to go here let's say const chats we're going to say if there is session let's say session. user if we have the user that is authenticated then let's just try to say await get users for sidebar so our function that we have created in the data in the data file now here we need to pass the IDE of the user that is in the session but now we have another problem so let's Auto accept this and here we would like to send the ID but in the session and inside the user we don't actually have the ID so I will comment this and I'll show you what I mean so let's say console.log the session and save this file and then here let's import that okay so let's take a look at the console what are we going to get if we visit this page let's refresh so we have the session. user right and then in the user field we just have in the user object we just have the name email and image how are we going to add the ID and in this case we want to have the ID that is stored in our database so we can go into .ts and we're going to add a callback that is session so let's go here put a comma and that'll go here so async session function and let's try to add the content for this function right we're going to add some body and in this body we will make it in a way that so that we have the ID field in this session so let's shrink our terminal and then this function will'll take in an argument so we could destructure that and take the session and then here we'll first let's have a TR catch then we'll like to connect to our database so connect to mongodb and then we're going to say if there is session. user so if it is authenticated successfully then let's try to find that user in our database so const user a wait user. find one and where the email is equal to this session user. email so that will give us the user and we will say if this user exist then what we would like to do is add the underscore ID field to the session so we'll say session that had the user field and then we're going to add theore ID field that should be user. uncore ID now here we have a typescript error that will fix and then we'll just say return the session and in the else case so after this Cur braces we'll just say else um so there was an error so let's throw it throw new error and instead of user not found let's say invalid session and in the catch again we're going to let me just actually copy and paste that so we're going to console log the error and we'll just return invalid session and that shouldn't be recession but session okay so now the problem we have is this underscore ID field and typescript says I don't know if this field existed on the session. user so we are going to fix this by overwriting this session type so we are going to go into root and create a folder called types and then inside this types we're going to have let's say oath. d. TS and that's how you overwrite types in typescript so d stands for definition and I will paste the file and you can grab that from the repo and how I solve this problem I just read the docs and they provided this uh code piece of code so if we save this now hopefully that should fix so here we have another error that says I think we are returning something in a wrong way let's just take a look okay so the error that we have is after this if check if there is not user let's provide an else and then we'll just throw this error that says user not found and we're going to get rid of that error so let's quickly reiterate what we did and why do we need this session function or call back so in our chat sidebar we oops that should be actually inside the chats okay we want to call this function that requires us to have the user already inside the session but inside the session we didn't have that ID field we take a look at that in the console the session only provides us this user field that has name email and image and we would like to add the underscore ID field to here so that we will be able to pass it into this function and in other parts of our application we also want to use that underscore ID field so that's why we went into oath. yes they provide us this function we first connect to our mongodb database then we try to find our user and then just add it into this session field if there was if we couldn't find the user we throw an error and if the session was invalid we just throw this error and return out of this function and then we had another error that says I I don't know this field if it exists or not so we went ahead and created this file and you can take a look at that in the docs so all this file says hey this session will have the user field just take everything that it has previously but also just know that it is going to have this underscore ID field that is string and this underscore ID was that ID that we get for from mongodb okay so that's going to be it for now let's go into chats and try to uncomment this and let's see what happens if we say console log the chats okay so we could delete this session and remember that should be uncore ID but not ID and we could save this now and let's take a look at this chats in the terminal so here we have a couple of different chats let's make this a bit bigger okay so we have have 1 two three four and five different chats so in our database we had six different users right but we only see five of them it is because we have exclude the current user which is the authenticated user so that's why we only see five of them now we're going to take it and send it to the chat component that will'll create in a second okay so inside the UR we'll try to just map this chats so let's open up Cur braces chats. map and then get each chat and return something for each of them and that something will be that chat component that we'll just create in a second so we'll like the pass a key so we could say chat underscore so chatore ID and then we could give just the chat so chat prop and here we can see we have Auto completes as well so that was the typescript specific now let's try to create this chat component under the chat folder so chat. TSX get the boiler plate and then rename this to be chat so this component will look a bit ugly and we'll see why but for now let's just take the chat as a prop and let's create that so we could use type chat props and that's going to be the chat for now let's say type will be any and for now let's say console dolog the chat okay we could save and let's see we're going to import the chat from this file and then we could pass the props so chat props so now here I will provide you a markup and you can paste it as well so I will just comment this out and I'll say starter code to copy and I will put the Tim stamp of this exact moment to here when I edit this video so here I'm going to paste that into the return field so return parenthesis and then just paste it then we're going to have a couple of Errors so let's fix them by importing next link the Avatar and an avatar image from our UI and and the image from next link okay so the only thing that we're missing is this user to chat variable so let's go and say const user to chat and remember that is going to be inside the participants array that we have um so we are returning this and the only value it has this user that we would like to chat with so we're going to say chat. participants and give us the first value and it only has one value so yeah and if we just save now hopefully that should work we're going to go here and there we go so we have the profile pictures of all of them and then the username now below the username we would like to show something like say hi to this user or the latest message if there is any and for this there are a couple of different edge cases and I have prepared something so that we can see okay so here are all those cases now here I sent the last message to jandoo and it is type of text and it is not opened in this case we sent this text as well as this icon but if I sent the last message it is type of text and it is opened then we show this icon as well as this open text and next to it we also show the uh create that field and then I sent the last message to Chan and it is type of image and it is not opened so Jane haven't seen that message in this case we show this icon this text as well as the created that date but if I sent the last message it is type of image and Jane seen that message so it is opened then this will be the icon and then we have the received cases now I received the last message from this test user and it a type of text and I haven't opened that message so this is going to be the icon and it's going to say show message when I click to that it's going to be received and here if the message is seen so it is opened we're going to see this icon as well as received text and then we have if the type of the message is image and it is sent from this user we're going to see this icon and if it is opened we're going to see this let me zoom in and lastly if we don't have any chat history with a user then we're going to show this icon and it says say hi so yeah this will require us to write a really ugly if else check so now let's try to add it and here we can see we have this formatted date and for this we need a function that I will provide you so before we do anything just go under the utils TTS and paste this function so format date that takes an input date that is type of date and that returns a string so the type of date will be something like this that we have in our database okay let me just copy this this and just paste it so it has two at the beginning so 2024 and this ugly date and we're going to take this and convert it into something like J January of 18 so this is what this function does I just explained the case to chat GPT and it give me this function I don't need to really understand what's going on so copy paste it from the repo under the .ts and then we're going to go into the chat and we have to write all those if checks now first let's just get the values from this chat that we are sending from our database so here I'll just paste it one by one so the last message is going to be under the chat. last message if this is not empty then give us the message type and we're going to assign it to this variable and then we would like to get this formatted date so if there is last message then call this format date function with the created that field and if there is not any then just take today's date format it and just assign it to this variable and then we're going to have two more variables so it is going to be a sender so we're going to check if the last message is not send by the other user that we're chatting with if this is not the case I will be the sender so this will be true and if the last message is opened or not will depend on this field now here we need two more variable one for message status and one for Icon component so the message uh status will be either send opened maybe received or show message or say hi right this is that message status and then the icon component will be these components so either this either this this this and all of these that we can see and this is going to depend to this if checks that we have a couple of more so I already prepared and let's try to paste it and this looks really ugly I don't know if we could type this in a better way and if you can just please share it in our Discord and yeah that looks pretty much ugly but that's the only way to get around this so we're going to paste this and let's import these svgs from the svgs folder that we have created previously so let's get this this one and you received is PG so if we save hopefully that should work but we need to add this Fields into our markup as well so inside this div where we have the full name we're going to paste this icon component message status as well as the formatted date and let's try to save this and try to see the end result so here we have so here in our sidebar we just see say hi for all these users and today's date and this is working fine because we don't have any messages for these users and the next thing that would like to add will be sent message functionality but before that let's just try to quickly understand what is going on on this file so we have got the chat as a prop and then from this chat we have created a couple of different variables so the user to chat that is under the participants array and then we try to get the LA uh last message so that might be null and in this case it is null for every user because we don't have any messages in our database and then we took the last message type so either text or image in this case it is null because still we don't have this last message and then we're going to format that date from the last message and are we the sender or if the message is opened and then we have two different variables that will change so we set light for them and the type of them will be string and icon component will be jsx element that we can see there are this jsx components and then here we say am I Des sender if so is message is opened if message is opened then we're going to show the open text else it's going to be sent and the icon component will depend on the message type so if it is text then we're going to show text message sent and we're going to fill it or we're not going to fill it so here we have fi current or just don't fill it and again it's going to depend on this field so basically whatever you see in this from line 22 until 45 is the exact same thing that we have type here so this is the translation of this code if you wanted to pause the video take a look at this and then pause the video here take a look at this and try to understand what is going on here and if that is matching with this one and I can say it is is matching because I have tested out off camera and yeah that took me a bit while to understand and just type this so don't feel bad if you don't really understand this immediately that looks terrible and ugly but that's the only thing that we can do in this scenario and then of course we just took those values and put it and display it under those P tags and then when we click to this links so each of them are a link when you click to them it is going to take you to that chat page and let's wait for it okay so for now we don't have that chat page that's why it's going to give us 404 but we're going to create that next and even before we try to build this Dynamic chat page there is something called streaming that we talked about previously in the server component section and it was this streaming so there are three different server rendering strategies and one of them was streaming so let's click to that so we already uh seen this where we we are rendering the rest of the page and we're just showing some loading skeletons for the partial content and can we do this in the chat page and the answer is yes so this sidebar takes some time to fetch these data from our back end from the database but at the same time we could see this uh rest of the rest of the page while this loads but now let's demonstrate this inside the chats let's say if we had a sleep function that will mimic some delay and while before we try to fetch this uh users for sidebar let's just wait for 3 seconds and again this is just a function that mimics as if for some delay and here I will copy this and I just close this so that we can see that in a better way so if we paste and visit this page now it is going to take 3 seconds until this loads and it is just because this component so this chat sidebar component blocks the entire page from loading and one way to fix this or I think the only way to fix this is using streaming and um this is how we would use it we will create a suspense that is coming from react and then we're going to put the chats so this will take some time to load and oops so while this loads we are going to put a fullback and that could be anything so let's say H1 and we're going to change this in a second so let's say loading and let's put three dots so if we save now hopefully it shouldn't block our page and here we can see so let's close this and then just paste this again and visit this page so we can see the rest of our page and while this loads and that's the beauty of streaming and if you want want to understand this in a better way just read the docs but that's the gist of it and just to have a better loading skeleton I will provide you again you can grab that from the G preo so we're going to go into the components and let's create one folder called skeletons and then we're going to say chats Dash skeletons oops if I can type correctly. TSX and then now I will copy it and then paste it into uh this component this is never going to change so just copy that and paste it and I will explain in a second but first we need to install this skeleton from Shaden so let's see what that even means we're going to go into Shaden and search for the skeleton okay it is this uh component that shows you a loading skeleton we are going to copy this and then into our our terminal just open up a new one oops that's a bit huge okay so we're going to just paste and it is going to install it in the background and here we are basically looping through five times and for each time we are just returning this div with a skeleton that is on the left that is rounded full and then on the right we have two um so width of 250 pixels of skeletons so the end result is something like this to be honest and we're going to just go ahead save this file and then we're going to change this fallback with the chats skeleton so let's say chats skeleton and import this then close that off now we can save this and let's take a look refresh the page okay so that's the loading con I mean that's the loading skeleton while page loads or the sidebar loads and we can see see the entire the rest of the page and we can even make this loading skeleton a bit better so if we just give pading X of three so ping X of three just adds um pading left and right about um 12 pixels that was the tail in CSS class now let's refresh and I think that looks a bit better so let's go ahead and delete that uh sleep function and like this okay we could save this file and I think we are ready to build the chat page so when we click to a chat we have this 404 page and that's what we'll be doing next okay so this is the chat page design that we will have at the end of the section in this section we're only focusing on the design so we're going to have this top bar where we can see the username the back button that will take us to the chat page and then we have this uh delete icon or button and then we have the message container where we store these fake messages and then we have the send message input component where we can put some text or on the right hand side we have this image uh I mean emoji pop over where we could just send some emojis so this is the end result that we are looking to build in this section so let's get started so this is where we left now we'll like to add that Dynamic chat page and let's say we don't know how to do it we're going to go into Do and search for something like Dynamic routes and here is the definition and Convention with an example so they say when you don't know the exact segment names ahead of the time and want to create routes from Dynamic data we can use Dynamic segments that are filled in at request time or pre-rendered at buil time and here's the convention you just put the folder name between the this uh square brackets and for example we have on the ID or the slug so we're going to go with the ID because uh in the URL we'll be holding the ID of the user that we are chatting with so we're going to go and under the chat folder we're going to create ID and here we'll have page. TSX now they say in the docs you can get the prems uh by default as a prop so we could go and do something like let's say rafc that will give us the B plate so let's say this page will be chat history page and we can get the prems so the type for this is going to be something like prems in ARS ID so we're going to get the type of string so I'm going to copy this and we are able to actually paste yeah this entire thing and then we'll just after this props destructuring them we're going to say hey we're taking a Prem that is ID it is because this is what we have named our folder and we could maybe show something like the prems over and then we could say prems do ID and let's see how that will look like so let's just put this okay we have a typescript error and to just get around this we could do something like this to have the arrow as a string okay so we're going to go ahead and try to see this page okay the prems are this and this is the ID that we have in the URL now this doesn't have any width and this is taking the entire Flex that's why this looks really ugly but we're going to fix it so if we click to this user the ID should change so it ends with um so 86 if we click click to this now it is 887 and if you click to this it just increments one by one and even ID changes so now that we know how this works let's try to add the markup for this page and since our focus is not designed and we already talk about this a couple of times in this course so in this section will be mostly copying and pasting code and by code I mean just CSS classes and some uh shats and components so no logic no next specific things only HTML and CSS and I just assume you are familiar with those so that we don't waste any time so I'm going to paste this once and I will uncomment this and again I need to just paste it again because this is the starter code that we will change later in the video so I want you to have this starter code if you're following along you can just copy this part and paste it and move on with the video so I will put a Time stamp here that we already did a couple of times before so let's say starter code for this file and then timestamp and while you're watching you will see this time stamp of this exact moment where we copy and paste it so now we need three more components which is going to be the top bar the chat messages and send message input let's comment this and comment this one and and build one by one so we're going to go under the components under the chat and we will create this chat Das toop bar file so that should be lowercased chat topb bar. TSX and again I will copy the content and paste it um not to here but into this file so I will paste this once and again and then I will copy this line paste it here the starter code for for this file and then timestamp so I'm going to uncomment this now we need two more components as well so the chat user info as well as the delete messages button so let's start with this one um the chat user info so we're going to go and say chat D user- info. TSX and then the other one was delete messages button so let's say delete Dash messages Das button and those are the components that I showed you at the beginning of this section now I'm going to go ahead and let's see what are we going to get the chat user info component right so I will provide you the content for this file I will copy it paste it once and then twice that will be the part that you would copy and paste it so I will put my notes to Here okay so uncomment this and that's it for this component we can save and we're going to we need to um just create this delete messages button component as well so here let's just copy and paste and complete this page and then we'll just I'll just walk you through every single component what's going on so here I copied that again I mean I paste that one again and I will take this comment and then paste it right here okay and that's going to be it for this component as well and as you can see no logic at all just CSS classes shat CN components and some hardcoded variables that's just it and that's the exact same thing that we do in other files but we'll explain that uh once we complete this uh once we build every component in this section so let's save this file again and then we're going to go here let's uncomment this I mean let's comment this and we have the chat to bar now if we save hopefully we should be able to see it let's refresh okay that's it we have the chat top bar and this is the chat user info component and then this is that delete messages button component so let's build the message container for this we are going to create let's see it was this component chat messages so let's take it uncomment this and we need to import it but first we need to create this file so chat messages. TSX and that should be messages and then this content is a bit long but bear with me I'll explain so I will copy it paste it once and then starter code for this file and then I'll just paste it again okay so we'll go here uncomment this part so we have some mock message messages array that just holds objects that has an ID that is incremented by one then it has content that says hello hey how's it going doing great how about you and then we have the message type as well as the sender so the ID of the sender and full name and depending on this values we are going to just check some variables and a little bit of logic but again we'll explain this in a second so let's save and then this this file is completed other than the send message input so save this file and let's see the output okay so that's what we see if we are the sender of the message it says me and the color is this um red color and then if this is the user that sends us message that's going to be color of blue and then we just have this border that changes uh one by one now let's add the send message input component which is going to going to be this one and we're going to import it so we're going to copy this file name and under the chat we're going to paste it. TSX and I will provide you the content for this so I will just paste it and then I'll paste it again okay so we could delete this okay from here and out you'll copy it and paste it so we will open this up and then now we need to import one more component which is Emoji popover that will show us so at the right top I mean at the right bottom corner we'll have that emoji pop over and that's going to be that component and then we have the input that we need to install from shaten let's first import the I mean let's first install the input we're going to go here and search for input and then we're going to get this command copy this so this is input component from chatan there's a lot of different variants that you can use and so that we got the uh command so let's paste it that's going to install input for us and then we can create Emoji popover at the same time let's copy this inside the chat we're going to go and Emoji Pop over. TSX and hopefully that should be our last file so I'll just paste it once and then with this comment let's say starter code for this file and then just paste it now here I'll uncomment this and hopefully that should be it but we need to install the popover component from shat CN as well let's go ahead and see what that means so pop over component so it is this component when you clict to that it opens up a popover and it has some content so in this case it has some inputs with some P tags maybe a headings but in our case we're just going to have those emojis so let's copy this command and we're going to paste it as well and then paste it into our terminal and I think that will install it in the background we could save this file and let's see okay this it's been installed let's save this file and finally this file so let's see and hopefully everything should work fine okay so we got the message input component as well as emoji pop over so we have all of our emojis one by one so that was a lot of copying and pasting I am really sorry about that but we just had to do this so that we don't waste all this time so imagine if you were to write all those components that was at least one to two hours so instead we just paste it and now let's go from the very B beginning till the very end and explain each component one by one so I'll just close everything and Shing everything we had the app folder first we created this chat folder I mean inside the chat folder we created this ID folder and that's going to hold our page so that page was Dynamic and for now it is a server component so here we have the chat top bar component so let's click to that this is this component that we can see here on the left hand side we have back button as well as chat user info component and on the right hand side we have this delete messages button so let's take a look at them one by one so this is that button that takes us back to the chat page and this is this is using the shat CN component with some classes so this is entirely just CSS classes and nothing else and specifically it is tail in CSS and then we have the chat user info component that has two hardcoded values so user full name that is jandoo and then user Avatar that is empty so we say if user Avatar is empty is undefined then show this logo. SVG from public folder and that's why we see this profile picture and that's literally it we just have an avatar component inside a div container with some CSS classes no logic at all and then delete messages button so we have a form that has the delete button and that delete button is holding a variable that is hardcoded and the value is false so we say if it is not pending then show this trash icon but if it is pending then show this ler icon so let's say if that was true and this will be true when we add the logic so when we click to that it's going to have this loading spinner for a second and once it is done once it delete the messages it's going to uh change back to the normal so it is going to be this trash icon so let's say false and that's it for this file and also it is client component is because we have this pending State and we're going to add some um hooks such as use form State and status and that'll be in the incoming sections so we could save this file close this and that's everything that we need to know about this chat to bar component so we could save this and then we're going to go into the chat messages component so here we just have a container that has some classes to give some uh styling with the background color as well as border color so we're going to go into this and let's take a look at this component so we have a mock messages array that is used for demo purposes that we have here so we'll just mapping through this array and this message array just Conn contains um so seven or six different messages and it has the content message type and then the sender information and in the incoming sections we're going to be fetching these messages from our database so here we have the session again hardcoded and then we have last message ref I think we could also delete this that is not really important for now um we'll be using that later in the course so here we have uh some logic we check if am I the sender if and just get the sender full name is message type of image and here we have something called is preview message from same sender and that affects the type of uh this border so the color how that should look like and we're going to get there and for each message we basically return this markup so if I am the sender then the Border color and text color should be this one and if I am not the sender then we're going to go with this blue color and if I am sender show the text me else show the sender full name which is coming from this messages array and then let's see what we have if message is image then show this image but if it is not then please show this ptag with the message content and here again we're just changing the Border left color and depending on this Mi sender field so here we have something called is preview message from same sender that I said will explain in a second now let's take a look at that so here we have messages um array that sender just changes alternates from one to two one to two one to two right so it is once me and then Chan once me then Jan and it goes in this order but what happens if this message was also from me then this border should go from at the top till the very end up until here so so we're going to go and change this for a second so let's say the sender ID is one which is me so if I save now we have three messages in a row that is sent by sent by sent from us okay so we're going to go here and there we go now border goes just like this up until here and since the user changes the Border just alternates and this is the markup that I have coded so this is how it works so here we have this variable and to evaluate this we check if the previous messages sender ID is equal to the current message sender ID if this evaluates to true then it means this is going to be true and here we have one check that says if index is greater than zero then please check this part it is because if index is zero then this will evaluate to minus one right so index is zero then and this will evaluate to minus one and in arrays we cannot get minus index so that is something that we had to add and then if this is false if the previous message is not from the same sender then we're going to run this part where it just adds this text of me or the sender full name so let's take a look so here we are in the first message so we do not uh so we don't check for this and then here we check if this message if the center of this message is the same with the previous one and yes it is so we just continue we do not add this part and then the same goes to this message the sender is same with this message as sender so we continue but when we came to this message the sender changes that's why we run this code block okay this will evaluate and then we add the sender full name and then again for this message the sender change es so we add this part and we just change the colors I hope that made sense that was pretty cool to code and I hope you could pause the video and just try to understand how this work and that's all we have for this component then lastly we have the send message input so let's close chat messages and then here we had um so we have one form that holds the input and before that we have this camera icon and on the right hand side we have the button as well as this Emoji popover so let's see we have this text message sent button and then this emoji pop over so here there is nothing at all going on other than CSS classes and Shad CN components so here we have Emoji popover and if you take a look at that we have some emojis and this is an array so we have source for each Emoji so in the public folder we have emojis so the like Emoji dislike mind blown and the rest of them we put the source and then alt then inside the popover we have we are mapping through this Emoji array and for each Emoji we just return this component which is a div that has the image so we pass the source the alt and then width and height and this is in a flex Flex container with flex wrap that's what why we have this kind of structure so it goes side by side and when it when it's about to overflow it just wraps so here the only important CSS logic that is CSS flex and flex wrap and here we have a pop over ref I think we are not using this at least for now but uh later in the course when we add the functionality we're going to be using this and you will see why that is and I think with that we are able to complete this section where we have added our chat page and I mean this Dynamic chat page we have all these components and we have design for them and in the next section we will just try to add functionalities one by one so I will see you in the next section let's start to this section by implementing the send message functionality now our messages can be type of a text or it can be type of images that we will show here and to store some images we need to use a service and in our case we're going to be using cloudinary so the first thing that you need is to just search cloudinary on Google and sign up if you don't have an account it doesn't require any credit card payment or anything like that it is free it is just free and you're going to get to here programmable media and you'll see the dashboard if you don't have a project then I think you should create it or they will immediately give you this information so you're going to go with the free plan that is the that is the default one and you're going to copy each this um secret or each this value and then we're going to go into the EMV file let's close this sh everything and in the EMV we're going to add cloudinary Cloud name and then we're going to put our Cloud name and then we're going to put the cloudinary API ke as well as API secret so let's grab all these values one by one I will copy this and then paste it into here and then I'll get the API key and then I will paste it here and then get the API secret and then just paste it now as far as I know the cloud name in API ke is not a secret but this one is a secret so you should have to have it as a secret and after this video I will delete everything so you can't use it please try to create your own now now I will save this file and then to be able to send a message we're going to create a server action so inside the actions let's create another one and that is going to be called as let's export it first that should be a lowercase export con send message action that is going to be an asynchronous function that will take the receiv receiver oops receiver ID that is going to be type of string and then it's going to take the message content and that's also going to be type of string and lastly it's going to have the message type that will be either image or it's going to be text and that's going to be an arrow function and we here here we have a typo so receiver ID and then here we're going to have try catch and the first thing that we would like to do just check for our session so const session a wait off and import it so we already have it or we just import it from off. TS file and then if there is no session then we could basically just return out of this function and then we're going to try to connect to mongodb so connect to mongodb and just execute this function and then we would like to get the sender ID which we can grab it so let's say sender ID from session. user doore ID that's the uh that's the field that we have added in this session callback if we remember right it is this one and then after this we're going to say now if the type of type of the message is image then we would like to First upload this to cloudinary and for this we need to have a package let's say mpmi cloudinary and we're going to install it okay so it is done and it is successfully installed now we have our um the environment variables and we would like to First configure it so I will copy something and then just paste it to here and you could just type it so cloudinary doc config and then you're you're going to create an object with Cloud name that is coming from process. EMV and then cloudinary Cloud name that is coming from our DMV file right it is this one and then we have API key as well as API secret now to get this cloudinary we're going to just import it so we'll say import Cur Braes V2 as cloudinary from the cloudinary package and hopefully that should work now we just connected to our cloudinary uh application that we have created and then uh below this we're going to try to check for the type of the message so we will say after the sender ID if let's give a bit space from here and also from here and I'll scroll a bit so if this message type is image so if message type is equal to image then let's just have a variable that is going to be a let upload response or let's say uploaded response and by default it's just going to be I mean initially it's going to be null and we're going to say if the message that user sends is image then let's try to upload it to our cloudinary bucket so we'll say await cloudinary do uploader do upload and we're just going to pass the content and this is going to return us a value so let's take it and say say uploaded response will be equal to this and then now we would like to get and so we' like to now create a message in our database so let's say const new message that is going to be type of IM message document from our models that we have created so import this from that and then so let me show that actually so import it from the message model and then the message that we're going to have um it's not going to be an object but rather let's say a wait message model imported. create that's going to take an object and then here each message had the sender field so I'll say sender will be equal to the sender ID and then it has the receiver so let's give the receiver ID and then the content so here we'll just say uploaded response. secure URL so this will give you the URL of the image if it is uh uploaded successfully but if this is empty so if message type is not image this will be null or undefined and then in this case we'll just take the content that is coming as an argument so maybe that will be something like hey how's it going so that text message and then we'll lastly just pass the message type for this message document and now after this we would like to add this message into the chat so here we'll say let chat and that's going to be let's say I chat document so that was our interface now let's say equal to await um chat model. find one so first we're going to check if this chat is existed and if it is not it means these these two users are chatting with each other for the first time so we'll say chat find one okay we're just going to get one chat in our chat collection and here is how we can do that so we'll say we the participants and then we'll say all operator that has the sender ID and receiver ID so find a chat in this chats collection where the participants includes the sender ID and this receiver ID okay so we found the chat now we'll say if there is not chat that means they are chatting for the first time so we're going to create one so let's say chat and here we can say it's going to be either chat document or null and then here we'll say chat a wait chat. create then that's going to be an object let's close it and then if we remember chat has the participants as well as the messages so that was the two Fields so we'll say participants will the will be the send ready and then the receiver ID and then the messages array will just will just contain the new message doore ID but if we successfully find a chat that will go into the else case so here we'll just add the new message to the chat right so say chat. messages. push and push the new message ID and then we'll just update it so await chat. saave so let's quickly go through what we what we have done here so first we check if we are authenticated or not and then we connect it to our mongod DP database we get the sender ID and then if the message type is an image so we're going to upload it to our cloudinary and here we're going to create a new message in our database we're going to pass the sender ID receiver ID the content if if that was an image that will be the URL of that image but otherwise that's going to be the text content and then the message type then we have the message but now we need to add the IDE of this message into our chat that's how we structure our database and then we're going to find this chat depending on this um condition so if the participants array contains the sender ID and then the receiver ID so we're going to find one chat if this chat does not exist that means they are chatting for the first time so they are just sending their first message in their chat history so if this is the case we're going to create that chat with the participants array and then the messages the first message will be this message ID and if this is the else case that means they already have a chat history with each other and we're just p and then we're just pushing the new message ID and saving it in our database and at the end of this file I mean at the end of this function we'll just say return the new message and there is something important here we need to add that is nextjs specific so let me just say prev validate path should be added to here and we will do once we get there so I just put this comment so that we don't forget and lastly in the catch we could say just throw the error and we could put something like console log error in send message with the error Dot message let's say and the type for the error could be any so that's going to be it for this send message action now let's see how we can use this for this let's close the. EMV we're going to go into our components and that will be the send message input so we had a form if we remember and then we had the input and this is a client component so let's create a state for this so const message content let's say and then set message content let's import the use state so we're using States that's why it's this uh a use client component and then here we'll just say the value will be message content and then on change we're just going to set this state so that's react specific we all know this and then here we'll say on submit then we're going to just let's say what should we call it handle send message so we could give any name here really so let's say con handle send message function and then it's going to take the event which is a form event that is coming from a form element so that we can get some autoc completes such as e do prevent default okay for now we can keep it like this and also we'll like to have a loading state so let's say cost is loading and initially it could be false so here in this function let's say this is going to be an Asing function it give a bit spacing then we're going to have the try catch and in the catch maybe you could just console log it and then in the try so let's say await and call our action so that was send message action and if we remember that was requiring three different um so arguments the first one is receiver ID so how are we going to get the receiver ID in a client component so for this there is a hook that we can use in next sh so that is going to be use prems and since this component is inside the chat page so it is under this Dynamic page right and we're able to get this ID and that's how we can do this so we're going to call this function or hook that is going to give us some prems and we can make sure the typescript knows what the Prem is so we're going to put this maybe carrot I don't know how to we call this but we're going to inside say ID it's going to have this ID field that is type of string and now we know this prems is an object that holds the ID field and this is called ID it is because that's how we called our so the so the chat folder that is dynamic if that was called something like X then that should be X as well but in our case it is ID so here we're going to get the receiver ID let's say const receiver ID will be pr. ID and then we're going to go here let's say that was requiring the receiver ID here it is then the message content which is this state that we have is coming from input and then the type of message in this case it is going to be text so after this we are going to say set message content to be empty and then we'll say set is loading to be false or maybe we should say that in the finally block so let's say s set is loading will be false and now depending on this loading State we could go into this button and we'll just say is loading should be this is loading okay I think this doesn't have the is loading uh prop in shaten so instead we could do something like let's first save this and then here we're going to have we're going to show this text message sent icon so this SVG if it is not loading so Cur brais is loading is false then show this okay but else if it is loading we're going to show um an icon called Loader 2 from Lucid react that has the class name oops let's first close this off okay okay so if it is loading then we're going to show this loader component then that will be height of six width of six animate spin so that is going to give us that loading spinner so we could save this file and is there is there anything that we need to add maybe in this input we could say it should be disabled if it is loading and I will put it after the own change so I think that's going to be for this file now let's save and hopefully everything should work fine we're going to go into here and let's say hello from the client and just send it okay I think message is sent so let's check it in our database I will refresh this page and there we go now we have chats collection as well as messages collection so in the chats we have one message that is just sent and we have the participants so these two IDs and then we're going to take a look in the messages we have hello from the client message type is text this is the receiver and this is the sender and that means now our messaging functionality works fine but let's see if we have that loading State I couldn't see that when we do it first so I will refresh the page and I'll say hello from client 2 and if we send it okay it doesn't have any loading States at all so let's see why that is so it is pretty obvious we didn't set this loading to be true at all so let's say set is loading should be true before we even try to do this operation so I will save and let's take a look so hi from client third and if we send this we have the loading and that disabled state so I'll just say one 2 three from client and here we can see it is disabled for a second and if we refresh here then we should be able to see all those messages okay but now if we check the chats we are not going to see that we didn't create another chat again so it's because that's the function that we wrate so here we said if there is not chat that means you are sending message for the first time just create that chat and that's what we did when we first sent the message but in the subsequent messages we just push the message into the chat and I hope that made sense and again we will explain this once we get there and now next let's try to add this functionality where we can send emojis as messages and since these are images we're going to save them into our cloudinary account and then we're going to get the URL and just save it into our messages so the content will be the URL that is referencing to our cloudinary account or the bucket and for this we're going to go into the Emoji popover component so here this is the component that we have now even though we are using hooks so we have use ref but this is not a client component so at least we didn't use the use client directive so even though we didn't use it this is still a client component it is because it is is nested inside this send message input component and which is a client component so whatever you put into a client component will be a client component so that's something that we already know but I just wanted to mention again so this is a client component okay so we're going to have is loading State and by default that will be false let's import the use State and we're going to have let's say that prems so const prems and we're using use prems that is coming from let's see next navigation and it's going to have this ID field that is type of string and we could immediately destructure it and get the ID and we're going to be using it and then we're going to have a function const handle sent message Asing function that is going to take a that's going to take an argument so let's say image URL that will be type of string and then we're going to call this function whenever we collect to this Emoji so this will take on click event let's add it to here as well so on click that will be a function that returns nothing so void and when we collected this div that has the Emoji we'll just say call the onclick function so on click to this div call this on click function which we will pass it into here so onclick it is going to be this function so handle send message and then just pass the Emoji do source and with this now we are ready to add the logic for this handle send message um function and even before that let's go into the button we'll just say this button should be disabled if it is loading it means while we are sending the message message that will be loading I mean that will be disabled and then let's cut this for a second and we'll say if it is not loading so if it is not loading then return this part but if it is loading then show this loader component and give the animate spin class so let's get this from Lucid react and I just want to have the height and width to be eight okay with with this we are ready to add this function so we're going to have the try catch as always and even before we try we'll say set is loading to be true and finally it will be false okay in the try now since this image URL is source that is in our public folder first we would like to fetch this and then convert this into a data URL so let's say const blob and then a wait fetch this image URL and then we're going to get the response and we'll say response. blob and with this blob we're just going to say const data URL this is something that we have done okay so this line we'll say await create file as data URL that was our function in our utils file so either it's going to be a file or a blob in this case it is this one and then we are going to get the data URL now we will call a wait send message action let's import it from our actions it's going to take the receiver ID it is in this case this ID that we took from prems and then the data URL and the message type is image now we're going to say const new message or for now we could just leave it like this okay I'll just put a comment we need to handle something here later okay we're going to add that part and in the catch we could just put some console log so I'll just paste it that says error from sending Emoji function and now if we save this hopefully that should work let's try and let's see okay so I just refreshed the page and I realized we have this invalid date error on the left hand side we're going to fix it in a second but before that let's just try to see if this emoji pop over works or not so I will click to that and just send an emoji we're going to have this loading state for a second and now it has been completed let's check our database if that worked or not so I'll refresh here and then the latest message is this type of image where we store the URL in our cloudinary bucket so I will copy this URL and paste it into a new tab and here we can see this is emoji that has been stored and we can even double check this if we go into our media library and here we can see this is the latest image that we're storing in our bucket so don't worry about these images that I was testing out before uh recording this video so you should be only seeing this image in your media library and then we had this problem of invalid date and the reason is in our messages we don't have the created and updated that Fields it is because when we we create our message model I forgot to add it so here that should be have this object where we just say time STS should be true and we're going to save this file and I think we need to shut down our uh connection is because we are using the cache connection right so we're going to just uh contrl C let's say CLS and then mpm run Dev and now whenever we create a new message it should have this create did that and updated that Fields hopefully that's going to work let's just try to test it out once more I will refresh this page so I will just send a message check if created at Fields work and just send it now if we refresh hopefully we should have today's date and there we go now in our database the previous messages the previous messages didn't have that created that field but now from here and out whatever whatever message we create will have the these two Fields And depending on that we can go ahead and just try to show this date so let's send in image and let's see if this is going to become that um so the SVG that SVG that indicates the latest message was an image so if we refresh the page here we can see now we have this icon that says we have sent this and it is type of image and this is the date and if you remember that was the part when we were wrri that if else statements so now we are able to send text messages as well as image messages and we're going to be able to send messages from this chat page as well when we click to that but we're going to get to that in a second and before that let's try to First add this functionality where we can fetch users information so in our data. TS file we're going to create one more function let's shrink this one that's going to be export const get user profile and that is going to be an asynchronous function that will take the user ID that you like to fetch so we're going to pass this user ID and we're going to fetch its user I mean its user profile so we're going to just create this function that's going to have the TR catch in the catch let's just throw the error and maybe we could console log it but that should be before the throw and let's say error in get user profile now we're going to first try to connect our data U mongodb database so say connect to mongodb call the function and then we'll say const user that will be type of I user document and then we'll say await user. find by ID and we're just going to pass the user ID and then we could have an if check so if there is not user we could just throw a new er error that says user not found but if this is not the case we'll just immediately say R return the user and I think we have a problem if we can't find it in our database then the type will be null right that's why that's what typescript tries to tell us so let's give a bit formatting and save it and that's the function that is going to give us the user profile and now we would like to use this so let's just try to close everything and rink so here we're going to go into the ID chat page where we have the chat top bar so here we could take the prems and let's say this will be prems that has the ID that is type of string and then we're going to pass this prems to top bar so let's see prems and the reason that we're passing this to topar is because we cannot get this prems from here so you just cannot come here and say give me prems it's because it only works in the page components so that's why we're going to come here and let's say prems and destructure it and we're going to say this will take this prop which is prems type of ID and string now here we can basically call that function await get user profile and then pass the pr. ID and that's going to give us the user data so let's say con user data will be equal to this return value and then we can pass this user data to into this chat user info component so user data and then just paste it once more and we're going to go into this function I mean into this component and let's say we are having the user data that is type of I user document and if we just do it like this that would give us an error so that should be user data then it's going to be a user document okay so just like this and then instead of this hardcoded data we could say something like user data. full name and then user data. Avatar and if we save it like this hopefully that should work we're going to save this file and then this one let's see if that is going to work let's refresh the page and here we can see this is the profile picture as well as the uh user full name so if we click other ones here we can see that changes and it just changes whenever we click to one chat but these messages doesn't change it's because all of them are hardcoded and we're going to fix it and let's actually do it now so again we're going to go into the data. TS file and create one more function and let's call it as export const get messages and here again async fun function that's going to take two arguments so the IDE of the current user which we can call it as me or maybe you could say o user ID but I just want to call it as me and then that's going to be type of string and then the other user ID we could say and that's going to be type of string as well and we're going to have this Arrow function and try catch as always in the catch throw the error as it is and then just say console log error and get messages and then in the try first we'll try to connect to our database okay we already imported that and now we are going to first find the chat between the sender and receiver so in our case it is me and the other user so let's say const chat and let's give it a bit space from here and bottom so chat that's going to be type of I chat document or is going to be null if we cannot find it so I will say await chat and let's import the chat model find one and here we're going to have the so if you remember we had the participants in chat documents right so we'll say where the participants includes me and this user so I'll say participants where it's going to have this all operator or query and we have the me and other user so instead of saying me I think we should say oath user ID that reads a bit more better so authenticated user ID and other user ID find the chat between them and then if we remember the chat had the participants and messages but both of those fields were just referen that means we're holding only the message IDs and user IDs so instead we would like to use populate method so say populate and then we're going to open up a new object because this will be a bit complicated or a bit more involved so we'll say where the path is messages populate this and then we'll say populate also the field let's say the path is sender and this is the type of model of user oops okay it's going to be like this and we'll cck to get the full name so we'll say select full name and we have to add this comma before here and lastly we'll just say if there is not chat then just return in empty array but otherwise just return okay we'll say const messages let's say chat. messages and then we'll just try to return those messages so let's try to understand what's going on in this function let's first save it to get this formatting and maybe we could make it like this okay so first we try to find a chat between the authenticated user and the other user we pass their IDs where we say the participants are these users and now that we have the chat we would like to populate the message Fields because the messages was only IDs right so let's say we had the messages array and those were only IDs so something like this and from here we cannot get the message content so instead what we say to mongus so we just say can you please populate it and that means just give us the content of the message so type of the message and every field that a message has and then we also say in the messages we had the sender field and that was also a type of reference right so that was an ID can you just give us the full name of that user because we're going to be using it when we fetch the messages so here we just showed the message content and then the sender full name that's why we use this populate method and if we save this now we are able to call this get messages function and for this we're going to go into our page so here we would like to call that function and if we remember that was taking the authenticated users ID and other user ID and to get the authenticated users ID we're going to call the session so aate off and that's going to give us the session so let's say const messages and we're going to say if there is session then call this function so await get messages and then we'll say session so let's import this function okay session. user doore ID and we could put question marks and then the other argument that it was requiring was the other user ID which you can get it from prems do ID and if this is empty so we could just return an empty array so if we don't have session that'll just be an empty array so that we don't get any errors and then into the chat messages we could basically just send it so let's say messages will be messages and I think we also need this session and we'll be using it so let's send the session as well into the messages let's go and just destroy Ure it so we could create a type for this so type chat messages props that's going to take the session as well as the messages so let's say messages will be IM message document and array of it and then we're going to have the session that's going to be type of session that's coming from nexo and let's get those so we're going to have first let's say chat messages props and we can get the autoc complete messages and session so we could delete this hardcoded value now and let's comment out this array okay I will shrink this so that if you wanted to you can get it in the repo but now we are getting an error from typescript so it says the messages is an array of IM message document and in this interface we said that the sender will be type of ID but we are trying to get a full name from an ID that is type of object ID and that's not possible but we can do this is because in our data so in this function we try to populate them so now we are not only getting reference so we're not getting only idees but rather we're getting the full name fied as well so we can go into our message model and we'll say this sender will either be type of object ID or it'll be a populated document and we can use use this so populated Doc and that's going to be coming from Mangus and we'll just say this is the I user document okay that's going to be the same for this receiver let's just add it I will copy this and then or paste that now with this we are going to get rid of this error and now typescript knows okay this sender might actually be populated and hopefully if we save this file that should work but we have an error here let's see and then we're going to say this is either going to be session or that's going to be null and let's see if we have any errors so maybe we need to add the populated doc here as well so or let's say populated document of this array it's not going to be null but rather like this if we say it like that and that should be okay and we can save this file as well and hopefully now you notice what this populated dog do now let's try to see the output in our end result in our application so we don't have any messages with Jennifer so that's why it's empty but if we click to here okay it says maximum call stack size exceeded and the reason that we're getting this problem is because I think inside the data and this is a problem that is related to nextjs I think it is not serializable so here if we just say json. pars and then json. stringify messages that should fix it we're going to go here and let's see okay I think we have fixed that problem but now we have another one and we need to add this host name into our next config.js file so we're going to go into the nextjs next config.js and this is something that that next want you to do so whenever you want to use these host names that you are showing your images then you have to added so we're going to go into the next config and we'll just try to say images and that's going to be an object remote patterns which is an array and then we could say the protocol will be https and then we're going to say the host name should be this res so the cloudinary so res cloud.com and hopefully that should fix it let's try to refresh okay so this is the output and it works pretty fine here we can see we have all of the messages from the very beginning till the very end and we are able to just render it now if we send another message let's say hey from client again the message has been sent but we cannot see it from here and this is something we can fix it so let's go into the actions and here we said that we're going to add this revalidate path so this is something we can call from nextjs again so revalidate path and we're going to just try to revalidate our data so let's say chat and receiver ID so it's going to say go into this page and try to fetch this again once you save this new message okay so let's test it out and we're going to understand in a better way so let's refresh this page okay we have the latest message now if we send another one once we sent the message it's going to save it into the database and then once it is done it is going to revalidate this path that means it's going to fetch the latest data for this page let's save and let's see if that's going to work or not and there we can see the message has been sent and we immed immediately see it here let's try to send an emoji which is type of image message has been sent and we revalidate our path and that's something you can see from the docs so revalidate path okay this allows you to purge cache data on demand for a specific path and here you can see there there are different kind of usages where you can so instead of doing in this way we could also do something like let's say revalidate path and that's going to be slash chat SL ID that was our so that was our Dynamic page and here we would like to revalidate the page or if you wanted to you could revalidate the layout and either you do it like this or this one both of them are going to work and we could go with this one so I'll just put a comment Okay so the alternative usage for the revalidate path function either this one or this one and we could delete this and that's going to do it for us now the other thing that we need to fix is when we click to a chat it doesn't have any loading state right it just waits for a second and once it is done it shows us and we can fix this by adding a loading. JS file so let's say loading. JS so this file can create instant loading States build on suspense and you would just create this file again a special file this is let's shrink everything inside the chat we're going to go into this page and we'll say loading. TSX and that could be any skeleton value and I'll just provide this file so let's just paste this and again there is nothing else other than CSS classes and skeleton component from chatan so here we have one skeleton for message topar and and one for container and then one for input the message input so there are some typos here let's fix it okay so what we do here is just adding a skeleton for all of them let's save this file so that we don't get this error and now let's see okay we already seen that but if we just switch to a different page here we can see we just have loading skeletons for top bar message container and then the message input here we can see and that's been the loading. TSX file and now we can also add the error. TSX file is because when you visit a page let's say this is a different user ID that we don't have in our database then it's going to say user not found and our application will crash so for this we can go and create this file that we had error. TSX and again I will provide that to you nothing else than CSS classes let's save this and let's try to see this in action so it tries to reload this again okay let's try to refresh this page and here we can see when you visit a page that does not exist it's going to give us user not found and if we click to this go back to chat it is going to run this uh link that will take us to the chat page so I just clict to that and here we have it but now we have one more problem that we just need to fix so if we just pass an ID let's say just this random ID it's going to give us a really weird message that users can't understand that users cannot understand in any ways so cast object ID failed for value and this error is coming from Mangus and we can fix this we're going to go into error. TSX so instead of fix this we could just say we are handling this error in a better way so let error message so initially that's going to be just this error. message which is this entire error and then we are going to fix this by saying if error. message if it starts with something like cast to object ID and that o should be uppercased if this is something like it starts with this one then we know user is not found and then we'll say this error message will be user not found and we can take this variable and then just pass it into here so it's going to be either the default message whatever that is or if it is C to object ID failed error then we're going to just change it and make it readable so let's give a bit space and save this file now we can even if we visit a URL That Is Random we're going to still get get this readable error that says user not found and that's something that you'll like to keep in mind when you're working with mongodb or and also I don't know if you have realized but when we send a message so let's say text message from client it doesn't only revalidate here but also it revalidates this part as well so I will send it we got the message here and then the icon changed and it's just been updated let's send a message to Jane as well hey Jane and here we can see it is just getting revalidated now let's try to add this functionality when we collect to this it's just going to delete this chat history between this user and us so in a real world application users shouldn't be able to delete the other users messages as well but here we're just trying to learn how to implement that so I think it is okay to add it for this we're going to go into the action let's go here here sharing this one and I think that's going to be our last action so export const delete chat action that's going to be an async and that will take the not the chat ID but let's say the user ID and we're going to try to have a try catch in the catch throw the error and maybe console log it error in delete chat with the message and let's give it a type of any and then in the try we'll say await connect to mongodb and then so here what would' like to do first we're going to get the authenticated user so const let's say session a wait and off so here we would like to just destructure the user and if we do it like this then what happens if this return us null then we cannot destructure it and this is going to break our application so instead we'll say try to get this one if this is null then just return an object and now we can destructure this value and that'll just be undefined but it is not going to crash our application so here we have a CO JavaScript trick that you could um just have it in mind and then we'll say if there is not user basically just return out of this function but then let's say const chat first we're going to find the chat between those users so a wait chat find one and you can immediately type it to here where we'll just say participants has this all operator with the user ID as well as this user ID so the authenticated user and then the user that will take to delete our chat with so if chat is not found again if there is not chat just return but now let's just try to get all the message IDs in this chat so const message IDs and I think we just need to give a bit space so that it is readable okay we're going to just try to get all the message IDs and let's say chat. messages. map and we're just going to get the each message ID then let's say message ID and convert it to a string because it a type of object that is stored in mongodb so we have the message IDs now let's say await message delete Min and delete delete every message that is in this array so it's going to delete all of the messages in this chat and then now that we have deleted the messages let's try to delete the chat itself as well it's because we have the messages collection and then chats now we deleted every message between those two users and now we would like to just delete the chat between those users as well so we're going to go and say a wait now we would like to just delete one chat so delete one and where the ID is chat doore ID and lastly now that we have deleted this we could just revalidate our path so let's say revalidate path which is going to be let's this time use this one so slash chat and then ID and then just revalidate the page and then what we would like to do so if we deleted every message in this chat then we will s it redirect the user to this chat page and we can do it by adding redirect not redit but that should be redirect to the chat page but if we add it like this we definitely going to get an error that's because this will throw an error that we talked that we talked about previously and whenever you want to use redirect most of the time that should be outside of the try or maybe all of the the time so if you add it like this then that's not going to give us any problem and we have I think we imported the wrong one it shouldn't be this one let's delete it and that should be coming from next navigation so again if you add this Reddit I mean if you add this redirect into the try let's say this will so this will throw an error because it internally throws an error so I will just put my comment here so that you know you shouldn't be using redirect inside a try and let's save this file now we need to call this function in our delete message button component and let's try to do it let's close those files that we don't use let's maybe just close everything and then we're going to go into the delete messages button now we would like to call an action on this file so we'll just say action and we'll just pass the delete m delete chat action but in this file we'd like to get pending State as well as error message state so instead we're not going to pass it like this but we'll say const that is going to give us the error message and then the dispatch function we're going to call the use form state that we already use and then here we're going to pass the this function as our dispatch and then we're going to pass the initial state which could be null and let's import this okay we already have but it says this want you to have an argument that is user ID but we cannot pass it we cannot just call it as let's say the user ID and let's get this user ID from our prems so I'll say use prems from next navigation and we could get the ID and now we could rename it as user ID right so that it is more readable and then we cannot call it like this and for this we can use the bind method so I'm going to delete this part and I'll create a new action or new variable not action I'm sorry so const we could maybe call it as delete chat action with ID and we'll just say delete chat action call it with bind method and the first argument will be null which is this and then we're going to pass the argument which is the user ID now we can take this let's say user ID as string so we could save we could say this is going to be type of string or we could say this prems will have ID that is type of string and that should fix it as well now into this action or the dispatch we're going to pass this action okay and that should fix it and we're going to call the dispatch here so basically what we done here we just said instead of calling this delete chat action inside here where we just can't pass the user ID so we created a new one by adding this bind method that takes the user ID and this is how you can fix this issue in when you're using actions that takes arguments so this is one possible fix and then we'll like to have the pending State we're going to go here and let's say instead of this hardcoded value use form status call this and then that's going to take that destructured argument that is pending and now that we have the pending field as well let's try to use this error message and that's something we already done so we're going to pass I mean we're going to paste it after this delete button I'll just paste it we have this text red 500 color with error message and let's save this file and hopefully it should work now we're going to go into let's say the chat we have with the jam and if we try to delete it we're going to have a loading State one for a second and we're going to be redirected to the chat page let's test it out we have the loading State okay the chats have been deleted the messages deleted and we are in the chat page and it even revalidated data so we see this updated icon and now just to make our application look a bit cooler I will go ahead and try to change profile picture of all these users in our database and then come back to the video and this is how I will do it I will visit random user. me and then just select an image copy image address and then come back to the users collection let's say we're going to change the Jane Avatar I will select all these contrl a and then paste that new URL if we say update that should be updated and let's refresh this page and here we can see the profile picture has been updated and I'll do it for this five other users and then come back to video okay so I have updated every single user Avatar and our application now looks a lot better than previous state now let's add this functionality so when we select an image currently we have this now when we collect in next we will take to fetch these users from our database now this is hardcoded and when we click to one of them we will be able to send the message which is going to be this image so let's go step by step we're going to go into the user I mean select user dialogue which is a client component it's because we are calling this inside the chat camera right we're calling this inside this component which itself is a client component so it means this is also a client component let's delete this handle send message function and delete from here and let's go step by step we're going to have a couple of states the first one let's say will be users and set users initially it could be an empty array and we're going to get the use State then we're going to have one state const selected user and let's say set selected user and initially it'll be null and the type of this will be let's say I user document or it'll be null and let's just type all those States and we're going to understand all of them one by one then we're going to have two loing states so let's say is oops is sending message and set is sending message initially that could be false then we're going to have one more loading State let's say const is fetching users and set is fetching users and initially that could also be false and lastly we're going to get the router from use router which is coming from next navigation not the router okay that should be this one and we're going to be using this um to to have some client side routing now in order to fetch some users we can go ahead here and say use effect and let's just initialize it on Mount and now what we can do here just create an file I mean just create a function inside the data. TS and call it but what I would like to show you is to create the route Handler so under the app under the API we're going to create one folder called chat and then I want to create one more let's say get users and we had to create this special file called route. TS and that's going to hold the uh logic to fetch some users right so export const and here we put some verbs which is get delete post or put so we're going to go with the get and that's going to be an async function and normally this takes request and response and the type of them is next request and then oops next response I think that should be the case let's just double check in the in the docs we're going to go here and let's say roud handlers it is this one okay it's the type of request not next request that should be request and then maybe response okay but I think we'll we're not going to use any of them so let's just delete it and in some scenarios you use them but in our case we don't let's have a try catch in the try we're going to have con session first we're going to try to get the session from o and if there is not session let's just return immediately out of this function and then let's connect to our database connect to mongodb and AIT it then after this we'll just try to get users so that we can show inside that card so const users and let's give a bit space from here as well okay that's going to be users type of user document array but that was our user document right let's import it then we'll say await user doind and that's going to find every user in our database if you wanted to you could size this but we could go uh with this one this is not coming from Lucid react so let's delete it that should be from Models okay we have users now we will say now we would like to filter ourselves so that we shouldn't be able to send message to ourselves so I'll say filter the authenticated us user from the list and to be able to do this we're going to create one one more array so filtered users users. filter get each user if their ID is not equal to the session user already then put it into this array so this will exclude the authenticated user and then lastly you'll just say return next response Json and this array in the cat we could throw the error and if you wanted to you could just put some console.log error in get users route Handler and let's just put a dash here and then the error itself okay now that's going to be our rout Handler to get some users let's delete this and then save this file we're going to go into here and let's create one function const get users it's going to be async function then at the end of this file we're going to call this function so that it executes right um inside what should we do so let's have a try catch even before we do any try let's just say um since we are trying to get the users we could say set is fetching users will be true right and then in the try we'll say const response let me just scroll so AIT fetch SL API now slash API slash chat SLG users so API chat SLG get- users and that's going to be our route and then let's um Json this so con data ra Json we're just extracting the data from the body and lastly you'll just say set users to be be this data and then in the catch you could handle this I'll go with logging it console log. error and finally we'll just say set is fetching users to be false and this is going to give us the users now let's try to map those users and show a user card for each of them so where did we use it okay it is this one so for now let's delete this div or let's just uh cut it so control X and we will say users. map and each user will be type of this I user document and we're going to return some GSX for it and I will paste it the thing that I just uh cut and we are missing some parentheses here let's give it a key so that we don't get any errors from react and that's going to be this user uncore ID and we're going to return a user card for each user and we can just pass the user into it let's say it's going to have the user and let's go into the user card component now we're going to take the user which is type of user let's say user will be I user document and now we can do something like user. full name and for the Avatar we could delete this and we could do something like user. Avatar and and that's going to be it at least for now let's save file and this one now while we are fetching users we could show some loader spinner and for this after this map method I will create another disc Cur braces I will say if it is fetching users let's return this part and I will open up this it's going to be a Dev with class name Flags justify center items Center so that it's been Center centered on the yeah it's just centered vertically and horizontally then we're going to have the Loader 2 component from Lucid react let's import it and then it's going to have class name of width eight height eight and then animate Spin and hopefully now that should work let's save and just preview it I will refresh my page and I'll select the image if I click to next I have this loading spinner for a second and here we have it we got all users in our database that we'd like to send messages now let's add this functionality when we click to them it's going to change the background and it'll indicate this user is selected now for this we are going to so we had this state called selected user let's create a function that will uh mutate this state so after the use effect we could say const handle let me scroll a bit handle select user that will take a user as an argument oops so user okay I cannot type clearly that's going to be user I user document and then what this will do is just set selected user to be this user and let's just make this a bit short by with this one liner okay so we're going to call this function and whenever we collect to this div so let's pass it into here handle select user and then pass this handle select user function this will take it handle select user and then let's say this is the function it just doesn't return anything void but it takes an argument which is user I user document and then when we click to this div we're just going to call that function with the user being argument and then to change this style let's say const is selected and this not going to be false but it's going to be dynamic so selected user this is another state that we should take okay so this is getting a bit complicated but trust me you'll understand in a second so let's pass this selected user as well selected user which is that state we have Above So selected user pass it and um so let's just take this and put it into its own type so I'll cut it create a type for this user card props and that's going to be this one um so I'll just delete those Cur braces okay so we have the user that is type of a user document we have handle select user which is a function that doesn't return anything and then lastly we're going to have the selected user again it is either going to be null or type of this interface and let's put this type into here and now this looks a lot cleaner so we'll say if selected user doore ID is equal to the user ID then this user card is selected and we're going to add just one class so I will give a bit space I put dollar sign and then if it is selected then we're going to add this class name so BG um Sig background feat hover but if it is not selected then just leave it empty and hopefully now this will work let's save and if I click to this um um okay now it's it's working so I collected this now it just selected and background is a bit different I don't know if you can realize it from the video but I can see it clearly and if I select the Jan the background changes and now she is selected if I click to this this one is selected this one this one this one so it just works and let me just quickly iterate what's going on so here we are sending into the user card the this function as well as the selected user state so when we collect to one of the user card this function runs with the current user so it's so this function set that uh user to be selected user and depending on that we are checking it and just changing the background color so now that we have this let's try to actually send the message so when we click to this button that says send let's say on click we're going to call handle send message function now let's try to create this function up here I'll say const function name is going to be async function and then it's going to have try catch even before we try let's just update the loading State set is sending message will be true and then in the try we're going to call our action which was send message action and it was taking three different arguments and let's see what what that was so receiver ID the content and the message type the receiver ID will be the selected user ID and then it's going to have the selected file and then it's going to have the message type in this case it is image so here the selected file let's see what that is it is coming as a prop and here we say um here we have an error that says it cannot be undefined let's just delete it then that's going to be type of string and if you remember we are passing this in inside the chat camera so when we are calling uh when we are calling the select user dialogue we pass the selected file that we already converted with this function okay that's something that we know we just reiterate it and then once this is done successfully we're going to take this user and navigate it to the chat page of this user and you'll see this in action in a second so let's say router. push that's going to be back ticks slash chat slash and then oops selected user ID and then in the catch you could handle this again I'll go with console logging it error and then in the finally let's update our state to be a false and we're calling this function whenever we click to this um send to button and we could make this to be disabled when if there is not selected user or when we are sending the message if this state is in their loading and we could also change this button content depending on this loading State and let's do it actually so we'll just basically add a loading spinner I will cut this for a second and then I will say if we are sending the message then let's return this part where we're going to have a loader to um so that was the icon that is coming from blet react and then class name of height six with six and anime spin uh class from tailwind and if it is not loading or I mean I'm sorry if we are not sending the message then we'll just return this part I will paste this and we have an error I think we need to just put it with a okay inside a fragment and if we just paste now hopefully everything should work fine so let's go and test it out I will refresh my page so that I can have a clean State I will select an image let's select this one again and I'll say next okay it had it had the loading State we got the users now our button is disabled it's because um so it is disabled because there is not selected user and let's go and try to send a message to jandoo I selected this now button is not disabled if I click to that we're going to have a loading spinner for a second because this will be true right and then in our function we will call the action and and just save this image to cloudinary as well as database and then take the user uh to this chat page so let's see that let's see this in action I selected this one and I'll click to this button we have the loading spinner and there we go now we are in the joho page we can see the latest message it is updated here and everything works just expected now here if you wanted to we could add one optimization that is when we click to this image we would open up a new dialogue and then just put that image into it so that we could preview this uh image in a better way now let's try to do it that was inside the chat messages component and here we'll like to have one state so I call this as is previewing image and this is a use State let's import that and as initial value this is going to be an object so we're going to have the open field by default fold will be false and then it's going to have the image URL let's say image URL that will be Source now initially again it'll just be empty and now we'll take to create a dialogue for this and we're going to go here um after this section after the messages we're just going to put our dialogue that is coming from our UI folder that we have it is from chaden now let's go here and just try to open open up one dialogue import it not dialogue close but that should be dialogue component itself I think I already imported that okay it is coming from here now inside we're going to have dialogue content it's going to be coming from UI and then we're going to have one image let's import it that's coming from nextjs now this dialog content or let's just go step by step this is going to have the open field let's say open and it's going to depending on the state then we're going to have this on open change function and we'll see what they'll what this does basically it just resets our state and this runs when dialogue uh closed and again we'll see that in a second now this dialog content will have a couple of class names so let's say class name maximum width of 4X large then height of let's say um 33 and then it's going to have background main I think background Sig Main and then we're going to go with border border color will be Sig color BG border and lastly we could just say outline will be none and for the image again we're going to have a couple of classes also here we're going to have AO focus should be false and the image source let's first add it so Source will be is previewing image. image URL and then it's going to have couple of class names um let's say object contain and then petting of two and that's going to be it for the classes let's say this should fill the size of its um parent and lastly we could just alt um that could be anything let's go with image and I think that's going to be it now when we clict to this image we would like to change the state so let's go here um this is that image component that we see on the screen so on collect C to this we will make the open so the open state will be true and the image URL will be message. content right so let's say on click we're going to call this and this will be true as well as image URL message content let's save and hopefully it should work I'll refresh this page and if I collected this now we have this dialogue where we see the image and if you wanted to we can close it so when we click outside um this function runs okay it is this one on open change runs and it just resets our state so that it it can close it and um just change the image URL to be empty so that was the first optimization now another thing that you could add let's say we have a lot of messages okay I'll say a and I'll just send a bunch of time okay so after some point now that I sent the messages it should scroll for us right if we we have let's say a couple of different messages and when we visit this page it shouldn't be here but rather it automatically scroll for us till the very end and for this again we can use use effect so let's try to add it now here we had something called last message ref and it has been added to to the very message and for the last message it has also been added now we are going to call a use effect and just scroll into that view so let's see what I mean we're going to create use effect and we're going to just run this whenever the messages changes so here I'll just say last message ref. current scroll into view and behavior should be smooth now if we save this let's see how that will look like I will go into this chat and if I come back to this it's going to scroll us till the very end but now let's send an image and it should again scroll for us till the very end but it didn't and to fix this we can add another function so for each uh message if it is type of image we could add something like this so let's say const handle image load so inside this function we'll just say last message ref. current scroll into view and behavior should be smooth now the isas that we're adding this is because rendering images can sometimes take uh I mean sometimes it can take a bit time that's why we need to just have this function and we're going to call this function so let's copy the name for image we will just say onload and just call that function now that should fix our problem hopefully let's see I will go and try to just send another Emoji Emoji has been sent and and it just scroll us scroll for us till the very end let's just change the chat and maybe just send hey for Jan now we're going to go and again take a look at this one it should scroll for us till the very end and that's the optimization that we just added so instead of just staying at the top when we click that message it all so when we click that chat it just Scrolls for us till the very end and it does that whenever we just send something random or or let me just send a new message as well and with this I think we have completed this application now there are some parts that is missing such as this button when you click to it nothing happens but feel free to add the functionality on your own so when you click to it an input file would open and then you would be able to select an image from your machine then when you send it that will call our server action that we have created so it is going to take the image save it to our mongodb database then it's just going to upload it to Cloud Nary bucket then it's going to revalidate this path so that the image will be displayed here as the latest message so it shouldn't be really hard to add but if you implement it that's how you get better while watching tutorials then you could add the search functionality and maybe after that you could add some pagination to this sidebar and just try to get familiar with the code base and try to add some features that is added by you and we would like to deploy this application but just before we do it uh there is something that I'd like to talk about which is no store function currently it is unstable and what this does is about caching so first let's try to understand the case that we have now in nextjs the static routes are cached by default so in our chat app I mean in our chat page the route page is the root page I'm sorry the the chat root page is static and that means whatever you fetch here will be cached now let's say fetch and I will paste some URL that will fetch the time for London now let's get the result con rest oops const rest await fetch let's make this an async function so that we can use await and we're going to get the let's say const data AIT R Jason now let's just display it just before the camera I'll say data do uh date time if we save now let's try to see the output if we go to our chat page so this is the time that we have if we refresh nothing happens right the time doesn't change but the seconds should increment I refresh again nope nothing nothing changes and it is because this is being cached and we can do this so nextjs does this caching so that our performance is boosted so we have a better performance in our applications but if we say we're going to have an object that will have let's say cash and we could just say no store or no cash if we save now whenever we refresh this page the time should increment by one or I mean it it should just update so now it is 32 22 if you refresh it just changes so this is the second now 33 34 I just refresh and it is not catched and you could either do it like this but if you are not using fetch so let's say you're using mongus to fetch some data and you don't want it to be cached so in this case you would call this function unable unstable no store now while you're watching this tutorial maybe it's already being stable and it'll be called as no store so let's copy this and if we go here that's how you would do it you would uh import it as no store and then just call that function into any component that you would like to not be in cached so this is the way you would use it and you can take this and even put it into our server actions let's go into our actions and I just don't want to here I don't want to just cach this at all so I'll say no store and call it current it is unstable no store um let's import this from next cache but if we wanted to we could rename this as no store and then just call it like this because this will be the name once it became stable so that's just something that I wanted to mention in static routes data will be cached and when you're using fetch you can use this option which is C cash no store or in or you can use this no store function that is currently unstable so when working with nextjs app rouer this caching can be really daunting if you don't really understand this so um just keep this caching in mind when you're building apps with next app router so I will save this file and now we are ready to deploy this application and of course let's not forget to delete those so I will comment out this or maybe just delete it completely like this okay now to be able to deploy this application we need to create a new repository so I will just call it mine as Snapchat clone and then I will create this repository as being public now we would like to commit everything that we have so I will open up a new terminal and let's actually delete console logs I think we have some console log inside the oath nothing in the the catch but let's see other than the catch do we have okay we could delete this one and outside of the catch we could delete all those okay so I think we don't have any okay let's delete this one or maybe we could just have them as it is okay so let's go here and open up a new terminal and I'll say get add all and then in git commit dasm and let's just finally control if we are ignoring our DMV file not modules and okay so everything looks fine now we will say get commit DM and I'll say app completed okay so I committed this now I will copy this command from my GitHub and then I will just paste it into to my terminal so that will push this code to my GitHub account so here I can see my repo has been just updated now I will go into my veral account and try to deploy this now go into your versal account and say create new project it is going to take you to this page and then I will would like to import this repo I will say import and here we can see we have some environment variables that we would like to add so we're going to go into here and just copy everything that you can see here on thism MV file and we're just going to paste it so here I will just paste it and it's going to take everything for us and I think we could delete this all URL and just leave everything as it is and then let's say deploy this application now this will build our application and then then it will uh deploy it if there is not any problem but if there is it is going to fail and we need to fix the errors and let's wait for it now so after 1 and a half minutes my application has been deployed now let's continue to dashboard there isn't any problems currently and let's try to visit now here we can see our application is live and hopefully that should work fine but it is not going to work so let's try to log in with GitHub and we're going to get an error let's see so we wait for it and it says um so you just have an error and the reason is we have to go into our o off settings and that was something that we have created so you would go under the settings developer settings then and select this oo application that we had so let me show that under the developer settings you're going to click to this o apps and select the application and now here we have the homepage URL that we would like to change it to something like this one right and that will be our homepage then we would like to change the authorization call back URL and we're just going to change this part with it like this and update the application okay so our application has been updated successfully now let's try to sign up again we're going to go here and sign up with our GitHub account so I have deleted every message in our database and every chat in our database so that we can have a clean state in production let's go with sign up with GitHub uh button or function and that's going to take us in into the application and here we can see everything should work fine now we can send messages to let's say Jennifer hey from production and send it it's going to revalidate the path revalidate the uh sidebar and then everything just works fine let's send some emojis here if we just send it we're going to get that here and it's going to update this sidebar we can send some messages to Bob let's say hi Bob and just send it and if you wanted to we could delete the chat history it's going to take us to the chat page once it is done and here we can see we don't have any chat history let's send an image from our machine so I will just select this image and send it let's say next and choose some user let's send it to Mary and if we say send to it is going to take a bit time time and here we have it message load we could preview it and everything works as expected so in case you have some caching problems in xjs and this is really possible to have because caching currently just sucks and for this I what I would do is take this no store function and just try to add the places that I don't like to have cached state so in my data. I basically add it into every function that's what I'll will save and I think I'll commit this after the after recording hey guys there is a quick pause here now I just realized we forgot to update this nav bar now currently we are logged out but we still see this log out button that should be something like login let's just try to update it that's going to be pretty short we're going to go into the Navar component and let's get the session that is going to be coming from oath file and we're going to call this function and now I will just delete this and instead I will paste about four lines so if we don't have the session then just show this button where it says login and takes us to the login page but if user is authenticated then show this log out button so that's it nothing else let's save and hopefully that should fix and I think this is the end of the course we have learned the most important features of nextjs app router and from here and out you should be able to build full stack applications with nextjs um I highly recommend you to read dos as you need and I hope this long course was fun to watch and easy to follow um thanks for watching and subscribing and see you next time
Info
Channel: As a Programmer
Views: 6,986
Rating: undefined out of 5
Keywords:
Id: 8c8nbc-5qpI
Channel Id: undefined
Length: 288min 21sec (17301 seconds)
Published: Tue Jan 23 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.