Let's Learn Next.js 14 - nextjs.org/learn Complete Course Walkthrough

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I've been wanting to learn nextjs for a while now and while I've dipped my toes a little bit here and there I haven't done a full dive yet and I just found out about next js. orgar and the course that they offer there to learn nextjs I figured this would be a cool opportunity for me to do this course record it so that you can follow along if you decide to do it and share my thoughts and opinions on it when I'm done all right so let's get into it now this is offered from nextjs it's their official course on how to learn this stuff they do recommend that if you don't know react to learn the react fundamentals and they also have a react fundamentals course that you can do on this same website NEX js. org learn but since I feel like I already know enough react I'm not a react developer I've mostly worked in angular I have fiddled around with react enough to feel comfortable enough to dive into nextjs nextjs is a react framework so if you don't know react you should do that fundamentals course but since I feel I'm good there I'm going to go ahead and just start with the nextjs course right away so let's start learning welcome to the nextjs app router course this is a free interactive course you'll learn the main features of nextjs by building a full stack web application what will be building kind of looks like a full dashboard there pretty cool pretty cool for this course we'll be building a simplified web version of the financial dashboard that has a public homepage a login page dashboard pages that are protected by authentication the ability for users to add edit and delete invoices so it looks like we're creating a crud app that has some authentication and login capabilities along with the homepage all right seems pretty cool the dashboard will also have an accompanying database which you'll set up in a later chapter by the end of this course you'll have the essential skills that you'll need to start building full stack nextjs app applications overview here's an overview of what features you'll learn in this course you'll learn styling optimizations routing data fetching search imp pagination mutating data error handling accessibility authentication and metadata prerequisite knowledge the course assumes that you have a basic understanding of react and JavaScript if you're new to react we recommend going to the react fundamentals course or foundations course system requirements no js18 or later and you'll need Mac windows or Linux uh in addition you'll need a GitHub account and a versel account okay so they're going to make you probably deployed to for sale I I'm pretty sure I have one I know I have a GitHub account but we'll see let's get started here all right chapter one getting started first you need to create a project to create a nextjs app open your terminal CD into the folder you'd like to keep your project and run the following command all right so MPX create nextjs at latest and then it's it's got the dashboard all right I'm just going to copy that and open up my terminal got my terminal ready I blew up the font size for for everyone who's who's probably going to watch this and can't see what the hell I'm typing in my tiny terminal window I got it nice and geriatric font size for you so I'm just going to paste that right into here I should uh CD into my projects folder all right so you need to install the following packages nextjs at latest yep I'll do that let's run in real quick installing all the stuff it needs to install all right success nextjs dashboard has been installed so I am going to go ahead and open my code C Editor to open that so I have a little Alias here that's going to help me do that that I've already got pre-installed and then that should open that in code where is it there's our next JS app we have uh all my other folders here a lot of stuff to look at co-pilot keeps wanting to activate it I haven't done that yet so not going to do that right now but here we go we got our next JS app app here's the structure got all this stuff here you got your public you got your node modules you got all your uh environment variables example here and you got all your config package Json stuff here which I'm sure they're going to go over in the tutorial right now so I'm not going to talk too much about that let's go back to the tutorial now that I've got this installed it wants us to CD into the project which I already did it says that unlike other tutorials that you have the right code from scratch much the code in this course is already written for you this better reflects real world development where you'll be working in a existing code base our goal is to help you focus on learning the main features of nextjs without having to write all the code sweet I like that um again this is for a little bit more advanced people not really beginners unless you already know react and have an idea of how to work in a code base and whatnot it might be a little tricky for you if you don't know how code bases are structured and how to navigate through a big code base so just keep that in mind if you're trying to do this uh here's the folder structure so you'll notice that the project has the following folder structure we have the app with the lib folder and the UI folder we have a public and the next config let's take a look at that real quick got your app with your lib and your UI folder there your uh where's that next config there's the next config folder here and what was the other one that it mentioned and the public folder there all right your app folder contains all the routes components and Logic for your application this is where you'll mostly be working your lib folder within your app folder contains the functions used for your application such as reusable utility functions and data fetching functions UI folder contains all the UI components for your application such as cards tables and forms to save time we've pre-styled these components for you your public contains all the static assets for your application such as images your scripts contains a file that you'll use to populate your database in a later chapter and your config files you'll notice that you have a bunch of config files as the nextjs uh the next config.js file at the root of your application most of these files are created and preconfigured when you start a project using Create next app you you will not need to modify these in this course feel free to explore these files and don't worry if you don't understand everything the code is doing just yet all right let's see placeholder data when you're building user interfaces it helps to have some placeholder data if a database or API is not yet available you can use the placeholder data in Json format or as JavaScript objects use a thirdparty service like mock API for this project we've provided some placeholder data in the app lib placeholder data.js file each JavaScript object in this file represents a table in your database for example so you got a little array with some Json objects in here you've got some key value pairs you have your uh customer ID uh then you have your amounts status dates and that's going to be your customer object or invoice object uh in that array and that's the structure of that data there in the chapter on setting up your data database you will use this data to seed your database populate it with some initial data typescript you may also notice that most files have a TS or TSX suffix this is because the example is written in typescript we wanted to create a course that not only equips you with the necessary skills to build robust application but reflects the modern web landscape it's okay if you don't know typescript will provide the typescript code Snippets when required for now take a look at the appli definitions. TS file here we manually Define the types that will be returned from the database for example the invoices table has the following types here's your type invoice a type invoice has an ID it has a customer ID an amount a date and a status this is to reflect your invoices here you can see that the structure of this um invoice has this type associated with it and you can expect that when you get an invoice and you pass it this type that it should return error free if you have all the appropriate properties that need to be in that invoice object by using typescript you can ensure that you don't accidentally pass the wrong data format into your components or database like passing a string to amount instead of a number I've been working in typescript for a while now typescript is awesome if you haven't learned it yet if you're still learning JavaScript don't worry uh take your time with it but I do recommend learning typescript because it is way better than JavaScript and will save you a lot of headaches in the long run especially when you're working in a big codebase with a lot of JavaScript if you're a typescript developer nextjs detects if your project uses typescript and automatically installs the necessary packages and configuration nextjs also comes with typescript plug-in for your code Editor to help autoc completion and type safety we're manually declaring the data types but for better type safety we recommend tools like Prisma which automatically generates types based on your database schema all right running the development server so you want to run mpmi to install your projects packages which I think should have been installed with the initial install of the project but just for the sake of this tutorial we will do what it says to do so we're going to go back to our terminal actually you know what I'm just going to use the integrated terminal inside of vs code so that I don't have to continue going back and forth here so let's go back to VSS code now I've got my integrated terminal up here I got to remember that there's people watching and if you can't see it then it's not very helpful now is it all right so mpmi to install our packages there like I said those should have already been installed with the initial install of the project that we did and now we're going to do mpm run Dev to run the project and now that's going to fire up our local environment oh crap oh my node version is off so I'm using node version manager and uh that lets me use different versions of node and I have mine set at version 17 and this requires 18 plus so now this should work since I've got the correct version of node running there we go now it's running in Local Host 3000 we can go check that out okay and then if you go to that URL Local Host Port 3000 you'll see that we have welcome to Acme this is the example for the nextjs Learned course brought to you by versel log in all right let's go back to the tutorial now and see what it wants us to do so after you run your local Dev environment it fires up on Port 3000 you go to Local Host 3000 and there we are exactly what we need to see we've completed chapter 1 on the chapter two on chapter one we set up our project and we got it running on our local Dev environment and chapter 2 is CSS styling currently your homepage doesn't have any Styles let's look at the different ways you can style your nextjs application in this chapter we will cover how to add a global CSS file to your application two different ways of styling using tailwind and CSS modules and how to conditionally add class names in the CLX utility package clsx utility package Global Styles if you look inside the appui folder you'll see a file called Global CSS you can use this file to add CSS rules to all of the routes in your application such as CSS reset rules sitewide styles for HTML elements like links and more you can import Global CSS in any component in your application but it is usually good practice to add it to the top level component in nextjs this is the the root layout more on this later add Global styles to your application by navigating to the app / layout TSX file and import the global CSS file all right so you're just going to copy this import here go to that file first in vs code so it said app where was I layout and it looks like we are just importing that Global CSS and then if we go back to our application we should see it now oh look at that look at that would you look at that looking nice all right now we got some Styles that's looking a lot better let's see what the next step is here with the development server still running save your changes and preview them in the browser your homepage should now look like this all right looks just like that exactly what we wanted to look like let's see but wait you didn't add any CSS rules where did these stop FES come from if you take a look at the global CSS file you'll notice some Tailwind directives so in the app UI Global CSS you'll see they got um Tailwind base Tailwind components Tailwind utilities um being called via directives there so let's go look at that file there and just see where that is uh for the sake of doing this tutorial where the hell did it tell me it was in the UI I really should pay attention uh UI Global CSS all right where is that UI Global CSS there it is all right so right here at the top you'll see that we have those three directives right there and those are the directives that are pulling in those Styles um into the application when we're calling them in the uh layout TSX file so we're importing that Global CSS here from App UI and and then those uh directives that are in global CSS are what's making it look so pretty all right so Tailwind Tailwind is a CSS framework that speeds up the development process by allowing you to quickly write utility classes directly in your jsx markup or TSX since we're using typescript the CSS is scoped to components so you don't have to worry about Styles collisions or maintaining separate Styles sheets that's right you just write it all in the HTML bloated HTML Files full of CSS class names but a lot of people like Tailwind so I can't on it cuz I haven't really used it so I can't talk too much about it um but just it does make your HTML super bloated I don't want to digress in Tailwind you add Style Elements by adding class names for example adding the class name text blue 500 will turn the H1 text blue that's just an example when you use create next app to start a new project nextjs will ask you if you want to use Tailwind if you select yes it will automatically install the necessary packages and configure Tailwind in your application if you look at app page TSX you will see that we're using Tailwind classes in the example so this is the example for app page TSX let's just look at it in the code so that we can reference the code itself uh so is that here God damn it what file page yeah I thought it was page oh yeah it's in the class names so here you go this is all this is all your uh your Tailwind class names here you see lots lots and lots of class names in your uh in your files there don't worry if this is your first time using Tailwind to save you time we've already styled all the components you'll be using let's play with Tailwind copy the code below and paste it above the paragraph element uh in the app TS all right so they want us to to paste this for the sake of doing the tutorial so what does it wants us uh above the P tag element all right where the hell is the P tag element here uh where's my BS code where's my P tag [Music] here all right I don't like that I'm going to format that all right uh all right let's see what that did oh well would you look at that added that cool little triangle there isn't that isn't that neat it wants us to take a quiz I think I missed a quiz on the first one let's see what the what did it add here we we know it added a uh a black triangle there right oh yeah that's correct okay if you prefer traditional CSS rules keep your Styles separate from your jsx or and CSS modules are great alternative so here we go CSS modules allow you to scope CSS to a component by automatically creating unique class names so that you don't have to worry about name collisions here is how you could create the same shape of the quiz above using CSS modules if you can you can experiment with using these modules in the following way if you'd like but we'll continue using Tailwind in this course inside the app UI you would create a new file called home. module. CSS and add the following CSS rules we're doing the tutorial right and I want to know how to use CSS modules in nextjs without using Tailwind so let's do it so let's go ahead and create this in our UI folder here so we're in our UI folder I forgotten a lot of my shortcuts here so we'll go ahead and create a new file home. module. CSS we'll create that in that we're going to go ahead and copy the example of the shape that they had there so I'm just going to copy that and paste that here so those are the Styles there I'm going to save that and then what are we going to do we are going to then import styles from that module into that page so then we'll go to page and we will import it right here so now we have styles in there and then we will take that div that I added here and there's my div there what am I what am I doing with this div anyways I'm going to do class names. styles. shape so then we can let's talk about it oh not last name class name all right so then let's save that and now we should see the same exact thing nothing should have changed in our little triangle let's look at our triangle to make sure it's still there yep so we have our triangle that's still there if we inspect that we'll see that it's using uh home shape uh style name there and there's the styles that we brought in right here from the module and how that works is that you have your home module here you have your class name there and from the module in the page you import it and you import that whole page with the name styles for your import and then you're calling shape from Styles right here so it gives it to you nice and neat right there and then the way that it renders because I haven't really worked with CSS modules too much so this is kind of new for me so I'm kind of talking it through or we can see it here we have home score shape double underscore and like a unique ID so then if we go back to the code and look at that we got the home module so that's where home comes from here and then shape comes from there I'm figuring out how it builds the names and stuff which it's probably going to tell me right now in the tutorial and this was probably pointless but I'm just talking it through because I haven't really used CSS modules all that much so that's kind of cool all right uh uh let's continue uh save your changes and preview them in the browser you should see the same oh so it did want me to do that I'm glad I did all right tailin and CSS modules are the two most common ways of styling nextjs applications whether you use one or the other is a matter of preference you can even use both in the same application all right let's see time to take a quiz uh what is one benefit of using CSS module uh increase the global scope of CSS classes to make them easier to manage across different files provide a way to make CSS classes locally scoped to components by default enabling better modularity and reducing the risk of styling conflicts automatically compress and Minify I think it's B that sounds right that's right they told us you know it's like back in school when all you had to do was actually read the thing and then answer it and you would know all right using the clsx library to toggle class names I got to I got to admit I don't I don't know what the hell clsx is so let's find out there may be cases where you will need to conditionally style an element based on state or some other condition clsx is a library that lets you toggle class names easily we recommend taking a look at the documentation ha who reads documentation I got chat GPT here is the basic usage suppose that you want to create an invoice status component which accepts status and the status can be pending or paid if it's paid we want the color to be green if it's pending you want the color to be gray you can use clsx to conditionally apply classes like this all right let's see here so what do we got all right so you import from clsx uh we're in a status component here so status the function takes in status and a string returns a span here we call in clsx we're passing in the Styles I'm guessing those are like the base Styles and then we add these classes based off of this condition so if status is equal to pending which is being passed in as a string then it's going to be gray and if it's equal to paid then it's going to be green okay okay I like it seems seems pretty straightforward I guess uh you can write your logic right in the class name instead of having a have like multiple elements and stuff for inline turn Aries with JavaScript and feels like less bloated I haven't worked and react in a while but like I like that that that looks cool time to take a quiz search for CLS in your code editor what components use it all right so now it's going to make us do something like this all right so let's just go ahead and go back to the just for the sake of doing the tutorial let's do a find all and do a clsx and then let's see what components are using using it okay see in the package lock I package Json where it's being imported here we go so our button. TSX um is importing CLS clsx clits no that's not that's not it CLA CLA CLA would you call it CL I don't know classics classics I have no idea what what the cool little uh name is for that what the the kids on the street call it class X I'm going to call it class X we'll see let me know if you know what the hell you call that um is it SQL or MySQL or SQL I don't know all right so here we go we got um we got the clsx there we have I made this so so big because I knew that I was going to be showing uh my screen that now it's like so big that I can barely see it um because the font's so big that everything's getting hidden in the and R and you know with these class names it doesn't really wrap so I got like these super long class names that just scroll for days but all right so we're it's being called here I'm trying to I'm trying to figure out so I'm not seeing the the logic or what what's where's the logic here so okay so that's being passed in and the class name so and there's the this class names for the style and then the props are coming in to the button component as class name and and uh so class name props is a Boolean is this a Boolean or a string oh that's right because you pass it in and then it's based off of the string that you pass in at least from that one example let's see another example here so here's another example of latest invoices oh this is commented out note comment in this code uh when you get to this point of your Cod course okay so okay CU you pass in the class name I'm GNA have to learn this I I I get it I get what it's doing I just I haven't really used it before so I'm not like used to seeing this so it's it's a little I don't know it's breaking my brain a little bit but here we're we're checking if active then gray else uh gray 500 all right so those those are some of the the classics I I like how that sounds I'm going to I'm going to call it classics all right uh all right cool so that's that we got that there and uh a damn it I was supposed to see what uh what files we're using it let's go back real quick to uh to vs code and see what files had it come on status status has it there all right so silly so silly trying to quiz me on this here status has it and pagination yeah okay cool other styling Solutions in addition to the es we've discussed you can also style your nextjs app with SAS which allows you to import CSS and sccss files and CSS injs libraries such as styled jsx styled components and emotion styled components I used those when those were like first popular I I don't know if anybody's still using those if you're using style components let me know I thought that that was a trend that died down um but yeah SAS SAS would be nice so you can write your CSS can you so I'm guessing you can do your CSS modules in SAS I wonder I guess I'll have to I'll have to learn about that not totally sure but that wraps up chapter 2 on to chapter 3 all right so chapter 3 optimizing fonts and images in the previous chapter you learned how to style your nextjs application now let's continue working on your homepage and adding custom fonts and a hero image in this chapter we are going to cover how to add custom fonts with NEX font how to add images with next image how fonts and images are optimized in nextjs why optimize fonts fonts play a significant role in the design of a website but using custom fonts in your project can affect performance if the font files need to be fetched and loaded cumulative layout shift is a metric used by Google to evaluate the performance and user experience of a website with fonts layout shift happens when the browser initially renders text in a fallback or system font and then swaps it out for the custom font once it has loaded this font can cause the text size spacing or layout to change shifting elements around yeah that's super annoying it's also it also happens a lot when a user has a slower internet connection you'll you'll see that a lot with people who don't have fast internet and sometimes on mobile devices if they're using their cellular data to load if their cellular data isn't fast you'll have to forgive me I caught a cold overnight and I might sound a little stuffy but The Show Must Go On nextjs automatically optimizes fonts in the application when you use the next font module it does so by downloading font files at build time and hosting them with other static assets this means when a user visits your application there are no additional Network requests for fonts which would impact performance that's kind of cool let's add a custom Google font to your application and see how this works all right so it's time for a quiz how does nextjs help optimizing fonts it causes additional Network requests to which improves performance no uh it disables all custom fonts it preloads all fonts at runtime it hosts font files and other static assets so that there are no additional Network request we we know what that answer is right all right add a primary font in your app UI folder create a new file called fonts. TS you'll use this file to keep all the fonts that'll be used throughout the application import the inter font from the next F font Google module and uh this will be your primary font okay so we're going to create that file fonts. TS and we're going to import inter from uh font Google so let's go to vs code and that's going to be in the UI folder so NBS code so we'll create a new file then fonts. TS create that and then import that let's save that file there let's see what the next step is the next step then specify what subset you'd like to load in this case Latin all right so then we create a export variable enter enter and then subset Latin all right so we'll just copy that go back to vs code right save that now let's see what's next finally add the font to the body element in the layout. TX file so we import it here from that export that we just created in that fonts. TS file and then we just add the class name enter. class name [Music] there all right cool so let's let's do that now so we go to layout. TSX where is that oh it's here at the bottom I need to just command p is what I wanted to do then I can do command P there we go that's what I wanted to do and then layout TSX and then I don't have to go around looking for it because that's how noobs do it use shortcuts kids that will make you a much better programmer more efficient all right so there's our Import in our layout file let's go look at the next step which is adding the class name referencing enter class name and then yeah put that on the body so let's see let's find that body there so then we're just going to replace this whole body tag there with this which adds uh the class name enter. class name anti-alias sized um not sure what that does honestly feel kind of dumb not knowing what what that does but um now let's go back to this and it says by anti- enter to the body element the font will be applied throughout your application you're also adding the Tailwind anti-alias sized okay so that's what that is it's from Tailwind which class uh which a class which Smooths out the font it's not necessary to use this class but it adds a nice touch to your fonts navigate to your browser open the dev tools and select the body element and you should see the enter and enter fallback are now applied under Styles and you can also add fonts to specific elements of your application all right so let's go check it out U make sure I saved that so let's save here we should see that change you saw that change there so yeah so it looks nice we'll we'll open up our Dev tools and inspect that and it was we put it on the body tag so let's look at the body tag here and then okay so we have our class name there and uh anti-alias sized uh there which you can see down here we have our font family and um the font style and then we have the um Tailwind class that was added there so cool looks nice looks looks sharp looks looks clean what's the next step let's see all right practice uh adding a secondary font now it's your turn in your fonts. TS file import a font called Lana Luana and pass it to the P tag element in your app. uh page. TSX file you should also uncomment that Acme logo component finally in addition to specify a subset like we did before you'll need to add specific font weight once you're ready let's expand okay so this is the the font we want to add so let's go back to vs code we'll go to our fonts fonts. TS I'm guessing it's from Google fonts so we should be able to just do that and then I don't know if this is going to work but we'll just copy that and then we'll uh we'll replace that name there and lowercase this and uh I don't know if it has a subset of Latin 2 but I'm going to follow the same pattern that we did for the inter font there and let's see where was it that they wanted us to put that again on the P tag somewhere hold on I'm getting lost here too many screens with the OBS uh let's see okay so it says they want it on the P tag in your page. TSX file and you should also uncomment the Acme logo component all right so we'll go to our page oh shoot uh all right so let's find page. TSX it wants us to add the style [Music] to the P tag here which I'm going to have to look how we did it in layout again so we just add this class name into class name and enter class name and then I don't know if it wants us to add the antialias sized as well but you know for the sake of doing it the same way that it was done here here's our P tag here and I'll add it to the beginning well got too many back ticks there and we're not going to do that we need to import the same way so from font appc there's just it's just all copy and paste that's all we do we just copy and paste I'm not going to type any of this stuff out but what was the name of that uh what is it what did I name it just noticed I didn't do that so let's do that and let's copy this and I guess I'm not going to have a subset here because it looks like it's throwing an error so we'll just do that save that go back to page and then Swap this out with that and then Swap this out with that and then ah why are you giving me a a an error here this is what's nice about typescript because it it is trying to call out what the error is but I'm not noticing why I don't have that uh see so so do I need to call it like a function but it's throwing that is it not coming so those are options and then the [Music] options doesn't have fall back at all so just weight is the only thing that seems to be required for the option here which I guess let me add a wait and we'll just do [Music] 400 so is a string all right that seems to be the only one that it's requiring there's our class name so now I don't have an error there so that should be good all right what am I what am I missing here preload enabled subsets specific for font please specify subsets or disable preloading available subset is Latin so I thought I did that and it was throwing an error and I don't know why I was throwing an error so let's go back to the fonts when saying the subsets is optional and it does seem that subset should be part of this um should be available but I don't know why I'm getting an error here argument types subset L is not assignable to parameter of type weight but I mean I see subsets right here which is optional weight doesn't seem optional though that's that's what I'm let's go back to 400 okay let's see if that fixes it okay so I don't have an error there anymore okay so I think that should resolve the issue that I had let's see if if it likes that or if I still get in error here okay there we go all right cool so that worked so you can see that the issue I was having here was that um the weight option was uh required and when I was passing in subsets you can see that if you look at subsets here like subsets has the question mark that means that it's optional and you don't you don't need to pass in a subset but the error that it gave me on the nextjs side was saying that it needed the subset of Latin but if you look at the other options in here that are parameters as part of this options object that you can pass into the font you'll see weight is the very first one here and it doesn't have a question mark a question mark meaning that you need to pass in a weight and that's that's what I caught there and that's why I noticed that all right well I didn't have a weight but I did have subsets so then when I added the weight of 400 it made those errors go away which again this is uh it's nice for for typescript and you know looking at my console right now looking at my terminal I can see that it was calling out that error and I didn't look at that which is a good thing for beginners if you're having issues look at your console cuz I I didn't look and I kind of struggled to figure that out on my my own and luckily I have typescript and the linting caught the um error in the linting OR at least I you know I I realized that weight wasn't optional and I had to enter a weight but if I would have just looked down here you see it was calling it out down here the whole time and I was just missing that so my bad but um you know that's part of the process so we all get stuck every once in a while but that's done so let's see reveal the solution to make sure we did that right okay so I didn't add the other weight I only added uh weight 400 on there uh but you see I imported the uh lucana font from Google the same way so I just added that to that import like I did in vs code and then um this is just formatted differently uh it's a little bit cleaner I did it all in line but it you know it's basically the same export const with the uh lucyana font calling the lucyana font and then passing in the options there's weight which is the one that I was missing was giving me the error and there's a subsets and we took Latin from that subset there and then in the page. TSX we imported the font and then we added the class last name the same way that we did previously oh it also called to uncomment the Acme logo which I forgot to do cuz I got stuck with that stuff so let's go back to page and where's that logo here we'll just uncomment that and now that's there and let's see what that looks like since I uncommented that ah there's there's the logo up here nice or or the logo right here the little Globe all right looks good all right yeah that looks like our same solution hence if you are unsure what options to pass into the font check typescript errors yeah that's what I did see uh uh visit Google fonts website to search for that to see the options that are available and then see the documentation adding multiple fonts yeah always refer to documentation when you get stuck if you get really stuck I could figure that out because it was just a typescript error and my uh text editor was calling the stuff out and so was my console so I didn't need to I wasn't that stuck where I had to go to the documentation so so now that we've added the two custom fonts let's see let's add a hero image uh to the homepage so why optimize images there's a lot of good reasons to optimize images mostly for performance so nextjs can serve static assets like images under the top level public folder files inside public can be referenced in your application if you look inside the folder you'll see that there are two images hero desktop PNG and hero mobile PNG these two images are completely different and they'll be shown depending on whether the user's device is a desktop or mobile with regular HTML you would add an image as follows we're in a page. TSX file here and if this was regular HTML we would just add an image like this with the uh Source attribute there and the alt tag for screen readers and people that need the alt tag screen readers but it's also uh if the image doesn't load give a nice description of the image so that people know what it was supposed to be uh how however this means that you have to manually ensure the image is responsive on different screen sizes specify image sizes for different devices prevent layout shifts as the image is loaded and lazy load images that are outside of the user's viewport instead of manually handling these optimizations you can use next image component to automatically optimize your images the image component the image component is an extension of the HTML image tag and comes with automatic image optimization such as preventing layout shifts automatically when the image is loaded resizing images to avoid shipping large images to devices with smaller viewports lazy loading images by default images load as they enter your viewport serving images in modern formats like webp and avif uh and when the browser supports that all right so what is the benefit of using the image component so it generates multiple sizes for images no it converts all images to jpeg no it deletes necessary images no it increases image resolution for better quality uh that sounds right a is the answer there all right add the desktop hero image let's swap the image tag with image component in your page. TSX file import the component next image and then add the image under the comment so let's take the import here that we're going to get and then we will go to vs code and then we are already in the page file here so then we'll just uh import image there and then it just wants us to swap out the image uh where the hell is the image do we have image in here am I not seeing it am I in the wrong wrong file where the hell am I let's go back to the to the tutorial so we're in page and then it wants us to add okay so it's just asking us to add it it didn't say it say swap it out it said swap it out right let's swap yeah well there is no image tag in there um but we're going to add it so so we're going to copy this here and we're going to go back to vs code and was there a comment here so it says add your your hero image here so underneath there we're going to add that format that real quick so it looks a little bit nicer here's your Source attribute there so it looks like we Define a width we Define the height and then we also have some classes that we've added there it looks like it by default it's hidden and then when you hit a mediums screen size which I maybe I just hover over it so it's just a media query the minwidth of 768 once it hits that viewport size it'll show that and then there's the alt tag all right uh let's save that let's go back to our browser and see what that looks like oh crap we got an error all right uh can't call Access original Factory undefined what did I do wrong so we've got the image there we're importing it from image here I'm not seeing any errors in the console let me just restart this Dev build real quick sometimes when in doubt that might fix it but if not it looks like let's see if it's something else I'm not sure why I'm getting a webpack error all of the sudden I mean it must be coming from that image tag um because obviously it wasn't there before let me see if it's the way I'm calling it or the way that I'm importing it this is kind of frustrating all right so it's definitely it's definitely coming from that from the tag itself let me uncomment that and save that and come back and whoa that was weird all right well I did absolutely nothing except comment that and then uncomment it I I restarted my Dev environment a few times before that I I don't know it's it's working now so I guess we're good that's a weird error to just get randomly I I don't know what caused that so if you come across this error when you're doing this tutoral and you're new and kind of uh trying to figure stuff out good good luck cuz uh it kind of had me stumped too and I don't know nextjs well enough to know why that might have happened but I I thought that that was kind of weird so all right well it's working now and I did nothing different except comment and uncomment that but hey we're good so we're good all right on to the next step let's go back to the tutorial all right so there we've added that now it wants us to what's the next step so we've added it we've given it the width it's good practice to set a width and height to your image to avoid layout shift um and there should also be an aspect ratio for Source images uh also notice the class hidden removes the image from the Dom on mobile screens and MD block shows the image on desktop screens and this is what it should look like which is what it looks like here on ours I'll close my inspector and you can see it's looking nice looking nice so let's go back to the tutorial now add a mobile image hero to uh to the same page now it's your turn again under the image you've just added let's add another image component uh for the mobile hero this image should have a width of 560 and a height of 620 and it should only be shown on mobile screens and hidden on desktop so you can use the dev tools to check out the the desktop and swap correctly once you've done that all right so let's do that right now let's go back to our VSS code and let's take a look here so basically basically all we're doing is is we're we're g to we're going to copy we're going to copy that and what was the height and um what was the height and width that they wanted so they wanted a width of 560 and a height of 620 so let's go back to with the 560 and a height of 620 and then we want to show it on mobile and then so basically we would hide it so this we would just do this and then on medium we would hide it and on and then we would just default it by block I'm guessing I don't know Tailwind so I'm just guessing that we're giving it a default of block since we're going mobile first and then once it hits uh the medium screen size where this would show then that that should be it this should be it so let's save that hopefully I don't get that weird error again reveal the solution just to make sure we did it right so you can see that what I did was exactly what I did there I just copied it over oh that's right I'm calling the wrong image so just something that I I realized I messed up there I am still calling the hero on desktop image and we actually need to call the hero mobile so let's just change this to mobile and then now it should look different different so then let's uh let's reload that real quick and then now we go here ah there you go okay so there you go now this is what the mobile image is supposed to look like I made that mistake um I was quick to jump the gun there and not not realized that I was calling the same hero image so on mobile that's what it's going to look like with the mobile screenshots in that hero image and on desktop it'll look like that and we can see that everything's working as it's supposed to be so our solution was correct now it's time to take a a quiz so true or false images without dimensions and web fonts are common cause for shift layout true here's some recommended reading that they have uh there's a lot more to learn about these topics including optimizing remote images and using local font files if you'd like to dive deeper into fonts and images see all these documentations that they have here awesome we have just completed chapter 3 on the chapter 4 all right so here we are chapter 4 creating layouts and pages so far your application only has a homepage let's learn how you can create more routes with layout and Pages here are the topics we'll cover create the login and dashboard Pages using file routing system under understand the role of folders and files when creating new route segments create a layout that can be shared between multiple dashboard pages and then understand what collocation partial rendering and Route layout are rout layout sorry so nested routing nextjs uses file system routing where folders are used to create nested routes each folder represents a route segment that maps to a URL segment here is how that works so your root segment would be your app directory and that's going to be your first slash there and then you have your url path for dashboard which is the dashboard segment which would be the first part of your url there and then that is in the so then the dashboard has invoices and then invoices is in the URL path nested within the dashboard all right and that's considered a Leaf segment so you have your root segment segment and then a leaf segment page. TSX is a special nextjs file that exports a react component containing the UI for the route in your application you already have a page file page. TSX this is the homepage which is associated with the route for slash so it's your root your root route root root I guess you could say root both way so that's that's confusing it's your route route your root route to create a nested route you can Nest folders inside each other with their own page. TSX files for example you have your app which would be your homepage right that's that's your root there and you have your page. TSX for that and then you have your login that has its own page. TSX H for that okay okay I get it I get it so here would be your app slash login SL page TSX which is associated with the login path let's create the page to see how this works creating the dashboard page create a folder called dashboard inside app then create a new page. TSX file in the dashboard folder with the following content all right easy enough let's just copy the contents of that file there open up vs code here and then in app we're going to create a new folder and we're going to name that dashboard and then within that folder we're going to create a new file and that file is going to be page. TSX and that page. TSX is going to have this content here which is exporting the page and what that's going to return is a paragraph tag that says dashboard page and to see how that works we are going to have to go to the dashboard path in the URL which I'm guessing that's the next step in the tutorial so yep so local Hol SL dashboard so I'll just go up here and see what we got there and then we'll do dashboard if I can type and then boom now we have our paragraph tag right here that we added there all right looks like it's working back to the tutorial so this is how you can create different pages in nextjs create a new route segment using a folder and add a page file inside of it by having a special name for page files nextjs allows you to collocate UI components test files and other related code with your routes only the content inside the page will be publicly accessible all right so for practice let's create some dashboard Pages let's practice creating more routes in your dashboard create two more pages we have a customer page this page should be accessible uh via slash dashboard SLC customers for now it should return a customers page element and then an invoices page so okay so this this should be fairly easy let's go back to vs code inside VSS code we are going to go into the dashboard directory we're going to create a new file called customers right is it customer or C is customer or customers customers okay so just fix that customers and then inside of that we're going to add a file. page. TSX and then in there we're going to just we're g to we're going to just do a little copy and pasting here we're going to do that copy this go back to the customers page paste that here and then we're just going to say custom m page there and then format that save that and then we're going to do an invoices page right so in the dashboard we're going to do a new folder in dashboard we're going to do invoices oh wait no no no that doesn't need to be capitalized invoices page there and then we're going to do a new file in invoices page do TSX there and then we're going to paste this here format that and then we're just going to do invoices all right and save that all of that is saved so now we go back to our browser and we're going to type in these pass to see so now we have dashboard SL customers customers page awesome and now we update that to invoices invoices page cool we got that going reveal the solution which should be exactly like how I did it so as you can see here you have your dashboard folder with your dashboard page there and then you have your customers folder within dashboard folder with its own page which leads to that path as we just saw and the same for invoices with the page there which leads to the invoices path wonderful and here's the solution which is everything that I just showed and now we have a a create dashboard layout exercise and dashboards also have some sort of navigation that is shared across multiple pages in nextjs you can use a special layout. TSX file to create UI that is shared between multiple Pages let's create a layout for the dashboard inside the dashboard folder uh and have uh a file called layout. TSX and paste the following code into it okay so at the dashboard folder here here so we're going to go to dashboard and we're going to create a file called layout. TSX and then in that dashboard we're going to add this block of code that they had us uh copy there and then we're going to go back to the tutorial which is going to be a side naav so okay so it looks like this snab is going to be across all those new pages that I just created so let's see let's break down what's going on in this code first we're importing snav component into your layout any components you import into this file will be part of this layout the layout component receives a children prop the child can either be a page or another layout in your case the pages inside dashboard will automatically be nested inside the layout and so it looks like this we have our dashboard up here we have our layout. TSX here with with our dashboard page. TSX here and then here we have our customers um directory with its page and invoice directory with its page that's what my VSS code looks like here so now we can check to make sure everything works so we're going to go back here and now you can see we're already in invoices here and you can see the sidebar um which you know it's showing you that it works but we'll go back to dashboard and there's our dashboard page that you can see there we already saw invoices so we should also see it in customers here and there's our customers page with our side nav here and this is coming together really nicely and it's uh pretty straightforward and and simple I'm I'm really liking nextjs so far all the uh tutorials that I've done before or the dabbling that I've done I've never really followed anything that was very structured and so far I got to say that this course is pretty nice it it lays everything out um fairly simply and and I'm liking it so far so one benefit of using the layout is that on navigation only the page components outside while uh only the page components update while the layout won't render in nextjs this is called partial rendering on navigation it preserves the dashboard with the layout TSX files and then rendering on navigation shows the page so it so it's basically preventing you from having to reload this stuff that is part of the layout so that will always be there you know it help helps with performance so you don't have to keep loading that same component on the sub pages that are going to be using that component so that's that's kind of cool all right so root layout in chapter 3 you imported the inter font into another layout app uh Slash layout uh as a reminder this is what that looked like we just did that so you probably remember that now this layout is required uh and is called in the root layout any UI you add to the root layout will be shared across all pages in your application you can use the root layout to modify your HTML and body tags and add metadata you'll learn more about that in the metadata chapter later uh since the new layout you've just created uh is unique to the dashboard Pages you don't need to add any UI to the root layout above time for a quiz what is the purpose of the layout file in nextjs to act as a global error Handler no to fetch data and manage State across the entire application no to share UI across multiple pages that sounds like the one and the last option is to act as an entry point for the entire application uh we are going to go with c yeah correct hey look at that we're done with chapter four that one felt like a a little bit quicker than the other ones we're on to chapter five all right in chapter 5 we are going to be learning about navigating between pages in the previous previous chapter you created the dashboard layout and Pages now let's add some links to allow users to navigate between the dashboard Pages my kids are in the background it's hard hard being a YouTuber when you when you got noisy little uh Rascals running around but it is what it is all right in this chapter we will cover how to use the next link component how to show an active link with the use path name hook and how client side navigation Works in nextjs all right cool this sounds like some neat stuff it seems like we're starting to get away from some of the more basic styling stuff and things like that and we're moving into uh more of how the inner workings work so let's see why optimize navigation to link between Pages you'll traditionally use an anchor tag HTML element at at the moment the sidebar link uses anchor tag elements but notice that what happens when you navigate between the home home invoices and customer pages in your browser did you see that there's a full page refresh for each navigation I did notice that I did notice that so let's see let's use this oh look at that you can see the it's kind of quick but you can see that there's there's a page load you can see the top up here there's there's some loading happening and you can see in the Dom here it's reloading each time we do that so that's that's not very performant and not very very spa-like the link component in nextjs you can use use the link component to link between pages in your application link allows you to do client side navigation with JavaScript although parts of your applications are re-rendered on the server navigation is faster and there's no full page refresh making it feel more like a web app here's how to use the link component in the uh app UI dashboard nabl links. TSX uh add the import link component in your okay so so what we're going to do is we're going to go to the links the nav links TSX component file and we're going to add this import so let's open up VSS code in vs code I'm just going to look for that nav links I'm not going to look through the tree here I'm just going to search for it because that's just a lot faster and here we're going to import link there and now let's go back to the tutorial and see what else it wants us to do and then now we're going to find the anchor tag that looks like this uh right here there's your anchor tag there and then we're going to replace it with link so basically all we're doing is just replacing that a tag with the link import that we just pulled in so let's go back to VSS code let's find our anchor tag here and we'll just VI a cool kid there select both of those and then link ah all right so there there's that and let's save that and let's hopefully it didn't break everything like last time I imported something from nextjs hey and then we'll make sure that this is now using the link it still says a tag but I'm guessing that it's using the link uh just to be on the safe side I'm going to restart everything because there was just that funkiness with the uh image component last time that I want to make sure that not experiencing something similar this time I'm guessing it just renders an anchor tag when you use that component I'm guessing that's all that does uh but yeah so I'm guessing that that's fine it's not going to show the component there uh but all right we're good we're good it it reloaded let's go back to Firefox and's see what that looks like reload that all right all right so now ah look at that now you can see there's no page load happening we don't have our little loader up there in the browser Fab icon um and it seems like there's no load everything's happening right there without having the browser refresh which is great all right so we got that working now and it says here uh pattern showing active links the common UI pattern to show that a link is active indicates that the user what page that they're currently on to do this you need to get the user's current path from the URL nextjs provides a hook called Ed path name that can that you can use to check the path since Ed path name is a hook you'll need to turn nav links. uh TSX into a client component add reacts use client directive on top of the file and then import use path name from the next navigation all right so we're going to import this used path name here this hook goes here so and now with the used path name hook we're going to see what's the next step here next assign the path to a variable called path name inside of your component so then now we create this variable using that hook just make that here why is it not like that says hooks must be called within a function is that not does it need to be inside that is that why it needs to be inside the return function is that correct I want to make sure I got that right make sure I'm not screwing this up yep that looks that looks right I needed to put it inside there uh you can use the class X Library introduced in the chapter of CSS filing to conditionally apply class names when the link is active uh when link href matches the path name the link should display with the blue text in the background Here's the final code for that all right so then we'll import that and then we'll add the conditional class name there if the link is the same as the path name and uh okay okay so there's link okay I see that so if it equals that we're going to add that class all right easy peasy let's do this so we're going to import this here back in PS code import that and then we're going to use it in our class name here which I think it was is that how we do it right is that right let wrap that see I'm trying to get ahead of myself here make sure I'm not screwing this up because I'm not really familiar with using that uh so we do it on outside I think that's what I did and then we add this here just make sure I've got that right right let's go back to vs code feel like I did something wrong oh might see why because this needs to be wrapped in curly braces there right is that right broke something so this needs to be in this needs to be in there's that and then we add that just making sure I got that so then guessing we need a comma there okay cool that and then now we add this then let me format that all right so there we got that all looking nice that looks right so we should save that and now this should work so let's go check that out uh yep so it's saved all right God dang it oh I forgot to add the use client directive that's right so it told me to do that and I forgot to do that and I do believe that I just need to do that at the top level of the file yep that's what it says there so let's go back to VSS code real quick because I forgot to do that step here uh here so then at the very top we'll do use client now save that now we should be good let's go back yeah there we go so now we can see we have that little highlight in blue there when something is active and we're on that link so you can see the Styles this sky blue 100 and text blue that's that's the styles that are being added with the clsx uh directive or hook uh but yeah there it's working all right sweet cool let's go on to the next step there all right so everything's working there now we're going to look into automatic code splitting and prefetching in addition to client side navigation nextjs automatically code splits your application by Route segments this is different from a traditional Spa where the browser loads all your application code on initial load splitting code by routes means that Pages become isolated if a certain page throws an error the rest of the application will still work furthermore in production whenever link components appear in the browser's viewport nextjs automatically prefetches the code for the linked route in the background by the time the user clicks the link L the code for the destination page will already be loaded in the background and the page transition will be near instant that's actually really cool time to take a quiz what does nextjs do when link component appears in the browser's viewport in a production environment well it just told us that right and it prefetches the code for the linked route I'm not going to read the other ones cuz come on we we we just went over that hey these chapters feel like they're getting shorter and shorter all right that that's chapter 5 on the chapter 6 all right so now we're getting into it let's see chapter 6 setting up your database before you can continue working on your dashboard you'll need some data in this chapter we'll be setting up a postgress SQL database using versel postgress if you're already familiar with postgress SQL uh and would prefer to use your own provider you can skip this chapter otherwise let's continue let's continue I've worked with postgress a tiny bit um so probably no enough but we're going to we're going to do this course we're going to stick to what they're recommending and we're going to use their versel postgress so let's see here in this chapter we're going to push your project to GitHub set up a versel account and link your GitHub repo for instant previews and deployments create a link to your project in a postgress database and seed the database with initial data this is I feel like this is going to be a big chapter here all right let's see let's see create a geub repo uh to start let's push your repository if you haven't already done so this will make it easier to set up your database and deploy you will need to set up your repo take a look at a guide on GitHub good to know you can use your G provider uh like gitlab or bitbucket or if you're new to GitHub we recommend using the GitHub desktop app to simplify it do that now and I'm going to have to initialize my my GitHub and get into my GitHub account because it's been a while and uh you know I don't really uh I haven't really been writing a lot of code lately so let's see here uh so I got to create a new repo here what the hell was the name of this um project nextjs dashboard so let's name that nextjs dashboard all right we're going to do that and we're going to just make that uh public whatever it doesn't matter we're going to add a read me now we're just going to we're just going to create that repo here and then uh where are we at we already uh I haven't initialized it it's been a while since I created a get repo but I'm pretty sure that I can just uh I'm going to have to do all this so let's go get in it on this here let's open a new terminal so we initialized it and then we're going to um oh I need to add get add add all those files and then so now we're going to do the commit all right there we go now we got our commit and then we're going to have to push it to this so we're going to copy that because we just created this uh repo and then this should just work it's asking me to authenticate oh crap what's my password there um not sure how much I was sharing of that um but I just I just set up my my repo and I pushed that to get and now we've got our get repost set up so that's all good I did my initial initial push everything's good to go now we're going to create a versell account uh I think I have one but but I'm not totally sure so we're just going to do that and go to verell do signup here and I I think I I did with my yeah so I'm here I got my okay I do have one all right cool we're we're all good we're all good there because I did that uh connect what do we got here what's the next step here connect and deploy your project next you'll be taken to this screen where you can select an import GitHub repository you just created okay so this is uh I think that's already linked up to my GitHub account cuz I see my GitHub account name there and then uh it says import so let's uh install this let's see this is a seems like they just want to authenticate here and then we'll just install that I need to check my authenticator app to to give it my code you know two Factor authentication kids you got to keep your stuff safe lots of hackers out there that uh take advantage of you so let's just go ahead and enter that all right looks like that's all good just going to pull up some of the stuff that I have here and I'm just going to import that one CU that's the one that they want us to import I'm just going to make sure that I I just deploying it yep select the name and then deploy all right so easy peasy deploy there see verell makes this very easy to deploy your applications but I've also heard that they're very expensive expensive um depending on if you're just trying to make stuff easy or if you've got a big fat bank roll with their hobby uh tier I think it's free uh so just keep that in mind it looks like it's building our application right now for prod and it's deploying what we got here so we'll just give it a few more minutes probably speed this part up and then just wait till it's done maybe go get some coffee all right sweet I'm back and it seems like it's done so let's just continue the dashboard there and then let's visit that real quick oh look at that we deployed our application how quick and easy was that sweet all right so back to the tutorial let's see here what's the next steps hooray your project is deployed we went there we visited it and you know it was uh linked up to your GitHub repo and made it super easy to deploy that which is uh it's pretty nice it's just super easy very simple although I don't know how much it would be to pay for that if it was a real production web app with uh with a lot of traffic but nonetheless it was simple so now we're going to create the postgress database next we're going to set up a database click on the storage Tab and your versel dashboard select connect store and create new postgress continue okay so this does really seem like the way that you get locked into doing everything in forell it it is super simple and easy and it's kind of nice that they they have it that way and you know for the tutorial sake we'll go ahead and follow along with this I know that you can use all kinds of different types of database services and whatnot like superbase and other um services like that or set up your own but again for the sake of this exercise we are going to just uh follow along with the steps here so what was it there so it says uh connect store create new postest continue so you go to your storage tab in your uh versel dashboard this looks like my versel dashboard where's the storage tab here storage and then uh connect store is that what it wanted us to do uhhuh and then we do our post Crest there uhuh and here's some other uh database Integrations that you can use there looks like a have KV config a blob and then we're going to go with postgress all right so then we continue and then here's some disclaimer but nobody reads those so we just accept blindly and then um do I have a region that's closer to me we'll go Portland you select as your database but this project serverless functions are running in Washington DC using different regions uh latency between I don't know why it's what whatever I mean I'm I'm not in Washington DC but if that's what it's going to say then I'm just I'm just going to do that so um let's see I'm guessing it's just telling you to follow those steps which is what we did just keep clicking the buttons and create and now once you've connected copy the contents from the Evan local tab uh on the database there so uh we should have a environment example in our code base and it wants us to copy this uh and put that in there I'm not going to show you guys that stuff because I don't want you using my database and and you know running up a crazy bill or anything like that so I'm just going to go ahead and hide some of this stuff right now but so now we'll connect and then here's our environment local so I'm not going to show this secret but I'm going to copy it and then I'm going to put that in my this is where you put put all your environment variables inside of nextjs I know this from from messing around with this a bit uh already you want to rename that to just EV EnV uh and saying e EVN was I saying EVN AVN am I thinking what what am I what am I talking about over here so EnV which is your environment uh folder and you don't want to uh append the dolal to it like I did you just want to change that to that because I think when you do it local it's just for your local this is actually what we're going to use for prod and then go to your get ignore make sure that your EnV file is ignored which we'll double check that and then we're finally going to run this in mpm install Okay so let's let's go back let's let's do everything the right way here so that I don't screw anything up so we're going to go to the EnV file where the hell did I put it oh here and I named it local remind myself to blur that out and now we're just going to make that EnV let's go to our get ignore and then just do a quick search here to make sure that it's being ignored all right cool so then that won't be committed to your git repo so that it will only be here which is great uh and then everything else looks good it wants us to run mpm install vers cell postgress I'm going to just kill my previous uh development environment that I was running I'm going to install that and then I'm going to run my Dev environment just to fire that back up a sh oh God damn it the my node version manager is really starting to bug me out I'll tell you that okay so then I'm just going to use that version so let's just do this copy that and be use now I can run my Dev environment so obnoxious so obnoxious when you use that and then you're on a version that's too late and I I I don't know there we go now I hopefully won't have to deal with that again until I need to use an older version of node which hopefully I won't be doing anytime soon and we're back we're back boys and girls we're back all right what the hell was I doing uh all right so we we ran that and we're we're good okay so now we're going to seed our database now that your database has been created let's seat it with some initial data this will allow you to have some data to work with as you build the dashboard in the scripts folder of your project there's a file called seed JS this script contains the instructions for creating and seeding the invoices customers user and revenue tables do not worry if you don't understand everything in the code is doing but to give you an overview the script uses SQL to create the tables and the data from place fer data JS file to populate them after they have been created in your package.json file add the following lines to your script so let's so okay so we'll we'll add this real quick in our package Json but I do want to go through those files just so I can kind of see if I can understand it sounds like it's just some SQL code um but let's go to package Json uh in our scripts we're going to add seed a little comma there um so that's that's good there here's our scripts directory here's our c. JS let's take a look at that a little bit oh crap I'm not I'm not showing you guys what I'm doing okay so basically I went to so we went to package Json we added our uh seed script there to run that when we uh type in seed to our terminal and then I wanted wanted to check out the scripts uh c. JS file here to see what we're what we got going on here so we've got our our DBS being defined up here by versel postgress we've got our customers invoices revenue and users here and this is uh being imported from the placeholder data in the JS where the hell is that in the app lib so that's being imported from this here which is our place holder data that we had which I think they talked about in the first few uh chapters of this but that's that's where that is I didn't save that let's save that so then we go back to seed here and it seeds uh so user seeds and then we're going to try we're going to uh do an an an a wait and then we're going to the SQL create extension if does not exist so we're going to give it a a goid uh con to create table T then we're going to do a create table if does not exist so here's just some SQL code we're going to use the uu ID and create a primary key uh varar was the name we got the email okay so yeah it's just seating it and here's all the the squl stuff that's that's being run to seed those um I know a bit of SQL I've used it a little bit you know I I don't know everything that's going on here but I I understand enough to know that it's just creating the tables and that's what the tutorial told us it's doing so let's just believe it uh let's go back now all right so so now that when we run this new script command that we added in there uh it will do what it does and it's going to run that that config and run that script seeds okay so then before we can run this command we must first do an mpmi bcrypt which is used uh to Hash the user passwords good yep should encrypt your your users credentials so so that you you know you do the right thing and use proper security so let's copy that real quick go back to BS code go back to our terminal paste that in there now we ran that that looks good what's our next step now in the tutorial now you run mpm run seed and you should see some console log messages in your terminal to let you know that the script is running all right so so mpm run seed let's see mpm run seed okay oh got an error God damn I just switched the node version what do you mean what do you mean this again seriously ah so obnoxious I I just I just took care of this I could have sworn I just took care of this all right now mpm run seed oh you son of a what's the error what error do I got connection ter unexpected what wait oh no what is the error now so let's see it says if you run into any issues while seating your database you want to run the script again you can drop any existing Tables by running drop tables name in your database query interface um executing query selections more the command will delete exploring your database so let me go like did that first one run and I just got an error with my my stuff or this is kind of obnoxious cuz this isn't my my strongest area and uh getting an error during a tutorial like this can be pretty frustrating because it can take me a bit to figure out what the problem is because I don't know too much about databases and if you're new um or new er to development and you run into something like this I can see it being very frustrating so I believe I did everything right I ran that I'm getting a no such user error so I'm not sure what that means oh my God so I just spent a ridiculous amount of time debugging this and the mistake that I made which you can prevent making is that when I copied the stuff that was in the secret file for the E NV local of the database that I was building off of I did it with this hidden um and I copied the snippet uh I I figured I needed to make sure that I got everything correct so when like I showed secret I I copied the user and I copied the password and that didn't fix the issue when I was trying to seat it but then what I did was I showed the secret and I copied everything by highlighting this and then just you know command C command V back into the EnV file in my in my uh VSS code in my project and you know ran it again because I was just like all maybe when I copied the snippet when it was hidden maybe it hid some other stuff that it didn't pick up on and yeah that fixed it so uh definitely just you know I should have not copied the snippet when it was hidden but it looked like when I pasted it like everything was there but then when I realized that the user was missing and the password was missing I was like maybe there was some other stuff missing from the rest of this when I copied it and now everything is working it looks like I successfully seated that table um or successfully seated the database and all those tables populated the data that I had from the example and now what I'm going to do is I'm going to run my local Dev environment because I'm assuming that now I should have some data since it's connected to that database my local Dev environment should be able to hit that and if I reload this and I'm on the customers page I'm assuming I should see some data in these screens or maybe you know what I might I might not have built out to display that data yet let me see if I can assuming that I'm going to have the hook it up into the UI so that it'll actually display it but I I'm successful i' I've got it so let's let's move on to the next part of the tutorial that was really painful I spent like 30 minutes trying to figure out what was wrong and it was it was my fault uh honestly it was my fault so now that we are still on chapter six here uh let's see so we seated our database we did that part everything's working now and then what was the quiz what is seating uh in the context of databases it's uh basically populating the data with the initial set of data that's what seating is so there you go there troubleshooting didn't help uh chat GPT was actually pretty helpful but the the problem again was just that I copied the wrong information there and I just had to make sure that I had the right information there um so now we're going to explore our database so let's see what our database looks like go back to versel click data in the side naab in this section you'll find the four new tables of user customer invoice and revenue so let's let's go back to verell I got to make sure I hide that stuff and uh where did where did it where did it tell me to go so I'm in storage uh and then uh go to the data in the side nav so project I'm not seeing the data side nav here so guess in storage here's that data there we go all right so uh uh where's it saying to go so it says data in the side naab uh in this section you'll find the new tables so we'll browse that so let's see so now we see that we have a user here with the with the email here let's look at other customers there's ah there's some customer data with that that stuff we populated for the customer data so we we're seeing our data in the data base and on those tables so now we can see the placeholder data that's great so let's execute a query here um you can switch to query Tab and then in the section uh for instance if you drop table customers you will delete the customers uh so be careful uh run your first database query uh paste the following in there so select invoice amount from invoices uh and then we're going to join customers on the invoices uh so here we're basically going to be joining uh the invoices and customers table based off of their customer ID where invoice amount is 666 Jesus Christ 666 a I'm not Canadian but I like saying that a every once in a while so let's just paste that query and run it so basically what it's doing is that evil rabbit they're funny um so yeah so basically what what this SQL command is doing is that it's finding the uh invoice amounts and the customer name and then wherever the uh customer amount matches the customer ID with this then it it's joining those two uh customers on the invoices there so uh that's that's pretty much the gist of that which customer does this belong to evil rabbit yes all right we've completed chapter 6 thank God that was a pain in my ass honestly I got stuck with that database issue and it was just something as simple as making sure I copied the right information from there um so if you run into that issue make sure that you have your uh you know don't have it hiding the information when you copy the snippet because that caused me a lot of trouble on the chapter 7 all right chapter 7 here we are fetching data now that you've created and seated your database let's discuss the different ways you can fetch data for your application and choose the most appropriate one for the dashboard overview page in this chapter here are the topics that we'll cover learn about approaches to fetching data apis OMS SQL Etc how server components help us access our backend resources more securely what network waterfalls are and how to implement parallel data fetching using JavaScript patterns if you use your own database provider in chapter 6 you'll need to update the database queries to work with your provider you can find the queries at uh in app lib TSS so if you decided to use your own database uh instead of using the versell database I I suggest that you do that so choosing how to fetch data the API layer apis are an intermediary layer between your application code and database there are a few cases where you might use an API if you're using third-party services to provide an API and if you're fetching data from the client you want to have an API layer that runs on the server to avoid exposing your database secrets to the client very important in nextjs you can create an API endpoint using the routes Handler database queries when you're creating a full stack application you'll need to write logic to interact with your database for relational databases like postgress you can do that with SQL or an OM like Prisma there are a few cases where you have to write database queries when creating your API endpoints you need to write logic to interact with your database if you are using react server components fetching data on the server you can skip the API level LEL layer and query your database directly without risking exposing your database secrets to the client here's quiz uh in which of these scenarios should you not query your database directly when you're fetching data from on the client when you're fetching data on the server when you're creating an API layer to interact with your database when you're fetching data on the client that is right there are a few other ways that you can fetch data with react and nextjs we won't cover all of them due to time if you'd like to learn more check out data fetching docs in the next section we'll explore how you can fetch data using relatively new approach async react server components using server components to fetch data by default nextjs applications use react server components and you can opt into client components when needed there are a few benefits to fetching data with react server components server components execute on the server so you can keep expensive data fetches and Logic on the server and only send the result to the client server components support promises providing a simpler solution for asynchronous task like data fetching you can use async await syntax without reaching out for use effect use state or data fetching libraries since server components execute on the server you can query the database directly without an additional API layer here quiz time what's the advantage of using react server components to fetch data they automatically Pro protect you from uh SQL injections they allow you to query the database directly from the server without additional API layer they require you to use an API layer to create endpoints the answer is B because that's what it just told us using SQL for your database project you'll write database queries using for cell postgress SDK and SQL SQL however you want to pronounce that there are a few reasons why we'll be using SQL SQL is the industry standard for query and relational databases EG om's General SQL under the hood having a basic understanding of SQL can help you understand the fundamentals of relational databases allowing you to apply your knowledge to other tools SQL is versatile allowing you to fetch and manipulate specific data the versel postgress SDK provides protection against SQL injections don't worry if you haven't used SQL before we'll have to uh we'll have provided the queries for you go to the app live. uh data uh TS file here you'll see where you're importing the SQL function from the roel postgress uh this function allows you to query your database so if we go to that file and we check that out so it's in the lib what is the the data so here you can see this import that's coming in there that SQL right there that's what we're we're talking about in the tutorial and uh you can call SQL inside any server component but to allow you to navigate to the components more easily we've kept all the data queries in the data. TS file and you can import them into your components what does SQL allow you to do in terms of fetching data fetch all your data indiscriminately Fetch and manipulate specific data automatically cach data for better per performance change the database schema on the Fly the answer is B all right fetch data for the database overview page here we go now that you understand the different ways of fetching data let's fetch data for the dashboard overview page navigate to the dashboard page paste the following code and spend some time exploring it we're going to do exactly that so let's just copy this whole blob code and we're going to go to the dashboard page so let's go to vs code we're going to go to dashboard and we're going to go to page here and now I think we're just going to paste that whole bit of code that we got there and let's just let's take a moment to just look at what we got here looks like we're importing a card component we're importing a revenue chart component we're importing a latest in invoices component and then we got that font that we were importing here looks like we've got a H1 tags saying dashboard and that font uh class name that we that we brought in we've got something with a grid here where we're going to show some cards that's commented out for the moment and then we got another uh grid here that's going to show revenue and invoices there so we're going to save that and I'm going to guess that it wants us to go to the dashboard page but let's just follow the tutorial so I don't get ahead of myself here uh the code above the page is an async component this allows you to use a weight uh to fetch data there's also three components which receive data the card Revenue chart and latest invoices that are currently commented out to prevent the application from erroring everything I just said all right so fetching data for Revenue chart to fetch the data for the revenue chart component import fetch Revenue function from data. TS and call it inside your component all right so we're going to go back to that we're going to copy this fetch Revenue function from the data. TS which we're gonna just paste that here we're going to save that but I also want to go to the uh data. TS real quick and then let's look for that fetch revenue and then here it says uh at no store so there's some comments here uh artificially delay the response for de purposes so there's that so then it says our data is an a wait call for fetching the type of revenue from uh the revenue table so we're selecting all from the revenue table and then we're returning we're returning the rows from that table if there's an error we're logging an error and then we're throwing an error there and that's what fetch revenue does so all right so now we'll go back to you know what I I got a lot of stuff open up here let me just close all this CU I'm starting to have too many tabs here and I'm having a hard time getting back and forth between everything and nobody needs that so let's just close all that and then I'm going to collapse all this because it's getting a little messy here so now we're going to go back to the dashboard all right so I imported that that fetch Revenue function that we were just looking at into this dashboard page here and the next step is to create to create a const for re using a weight here and importing that or and and setting that inside the uh page component there so let's go back to vs code so we're in here and we're just going to paste that right into there and let's go see what the next step is all right then uncomment the revenue chart component and anything inside the revenue chart function uh check your local host and use the revenue chart data in your component Okay cool so let's go back to vs code there a lot of this back and forth that we're going through here so here's our Revenue chart component that's commented out we're going to remove those comments and we're going to just save this and now we're going to go back and see if we have some data showing in our Local Host go back to the dashboard we're currently in invoices and paste that there's there's a bit of a load there uhoh uhoh I'm not seeing anything we got any errors there what am I doing wrong here all right let's go back to vs code and let's look through the code and see what I'm doing wrong here so I obviously have Revenue chart here right this is my dashboard my Revenue chart component oh God damn it [Music] I obviously wasn't wasn't paying enough attention to the tutorial and I was getting ahead of myself because we have all this com commented stuff and it did say to go to revenue chart component but to uncomment that stuff but I just uncommented what was in the dashboard which totally makes sense now so let's just I'm sorry I'm sorry people so you know just try not to get ahead of yourself try not to to Jump Ahead like I did and and pay attention to what the tutorial is saying because now I see that I didn't have any of this uncommented so that will explain why nothing is showing up I'm pretty sure now if we look at this we should see something on the screen there it is yay we did it we have our component and our Revenue data showing there that is awesome great On To The Next Step geez all right let's continue importing some more data queries so fetching data for the latest invoice uh for latest invoice component we need to get the five latest invoices sorted by date uh you could fetch all the invoices and sort them through uh using JavaScript this isn't a problem as our data is small but if your application grows it can significantly increase the amount of data transferred on each request and uh the JavaScript required to sort through it increased instead let's sort through the latest invoices in memory and you can use SQL query to fetch the five latest invoices for example this query we have in our uh data. so uh latest invoice is raw so we're selecting invoice amount customer name customer URL an email from invoices and we're joining them on the invoice customer ID when the customer ID matches and order by invoices date descending limit five okay easy enough that makes sense and then in your page we're going to fetch the latest invoices so we have since that's coming from the same lib data file we're just going to add the um import for the fetch latest invoices in that file just like we did for the fetch revenue and this time I'm not going to screw everything up like I did earlier so we're just going to add a little comma here and then we're going to fetch invoices there and then what was the next step no I think I know the next step but I want to go back to the the tutorial which is just going to be to comment everything out but let's let's just keep following along so then uh uncomment the latest invoices component and you'll visit and your local host and you'll see all the latest invoices here so let's do that so we'll go back to BS code and let's uncomment everything out from latest invoices this time I am not going to screw around and I'm going to go to the latest invoices component and make sure that you see all that all that stuff that's commented that I missed on that Revenue one uh we're going to uncomment here and then all right so now we should be good we should have all the stuff that we need to see let's go back to our dashboard oh oh here we go oh I didn't import latest invoices into that page file so that makes sense uh we'll go back here to page and we got to just how we did fetch Revenue here we got to do um invoices uh from Fetch latest invoices is it and then we'll just we'll call that invoices right or what what are they using what are they calling latest invoices so copy that that so then we'll just change that there all right so now we should be good let's go back and see what we got here ah there we go all right loaded up nicely updated just now everything's looking good looking real good all right then uncomment the latest invoices component we did all that visit you'll see that we have our our five our five uh invoices there and now we are going to fetch the data for the card components now it's your turn to fetch the data for the card component components and we'll do the same thing the total amount uh total amount of invoic collected total amount of invoices pending number of invoices total number of customers again you might be tempted to fetch all the invoices and the customers using JavaScript to manipulated data but for example you could use array length and get the total number of invoices and new customers so we can set something up like that and then but with SQL you can fetch the data you need with a little longer using a query uh uh that's it's a little longer than using query length but it means that the less data will be transferred during the request so here's a SQL alternative so you can select count all from invoices and then that and the function you'll need to import is called Fetch card and you will need to destructure the values in return hint check the card component to see what data it needs so once you're ready um expand for the toggle the final code okay so we're going to copy this here we're going to go to our data .ts here do we have anything for so here's fetch card data okay so actually that's already all here so we have uh wait is it is that the same stuff that it had us copy let me see so yeah so we have that so we have uh we have that already okay so if that's already there so we don't need that because it's already here um so what does it want us to do just do the same thing we did for cards which is go to the page. TX and then so it would be like fetch card is it it wanted us to fetch like all of that stuff right like it wanted us to fetch card data is it just fetch card data sorry got to go back to the tutorial I wasn't sure if it what it wanted us to do so so we'll do the import card data and the structure value okay so so that's that's pretty straightforward we'll go back to vs code basically wants us to do what we already just did so then so this is what what we're doing here we're going to basically call all of those from that function damn it because those are all part of that fetch card data yeah so these are all coming from this fetch card data so we're we're going to be calling those from that and then trying to get all this here so then that should do that and then we should be able to do this and then oh come on right so I got to comment this out one by one okay so that should I'm going to format that to look a little nicer I think that should be everything we need to do that let's make sure I didn't break anything where are our cards ah there's our cards okay so you can see that I imported okay so just talking about that real quick so I imported all of these from that uh fetch card data function and all of these come from Fetch card data that's inside of here so you can see like the total number of invoices all of these are returned by that data within the fetch card data function and you've got all of that there and that's what's returning all this here which is what you you see you got the return here and that's what this function does it returns all this so then I am calling all of those in here from this import and then I am pulling those values here to display in the cards and that's and that's what makes those cards up here start showing all right awesome make sure I did everything right we'll look at the solution which I did fetch card data as you can see I I called I set those variables for all of those items that are returned from the fetch card data uh function and then I I commented out this stuff from these values that are being called in here and that's that great now you fetched all the data for your dashboard overview page your page should look like this it sure does isn't that great however there are two things you need to be aware of oh no the data request are unintentionally blocking each other creating a request Waterfall by default nextjs pre- renders routes to improve performance this is called Static rendering so if your data changes it won't be reflected in your dashboard let's discuss number one in this chapter and then look it into detail at number two in the next chapter so what are request waterfalls a waterfall refers to a sequence of network requests that depend on the completion of a previous request in the case of data fetching each request can only begin once the previous request has been returned or has returned data so sequential we got uh fetch Revenue fetch latest invoice and then parallel and here's time for example you need to wait for fetch Revenue to execute before fetch latest invoices can start running and so on so so here we have fetch Revenue runs first then it waits for fetch Revenue to finish and then this runs and then the fetch cards waits for invoices this pattern is not necessarily bad there may be cases where you want waterfalls because you want a condition to be satisfied before you make the next request for example you might want to fetch a user's ID and profile information First Once you have the ID you might then proceed to fetch their list of friends in this case each request is contingent on the data returned from the previous request however this Behavior can be unintentional and impact performance when might you want to use a waterfall pattern to satisfy a condition before making the next request to make requests simultaneously to reduce a server load by doing a fetch at the same time it is number one we just read that come on people all right parallel data fetch a common way to avoid waterfalls is to initiate all data requests at the same time in parallel in JavaScript you can use this uh with promise all or promise all settled functions to initiate all Promises at the same time for example in data. TS we're using promise all uh in the fetch card function okay so you can see here's that fetch card function and then we've got those uh those SQL queries here and then the con data is in await promise all and then it pulls all of these from those up there good to know with promise all settled you can also run an array of objects with the status and value keys so that you can check a promises status is fulfilled or rejected before passing the value to your component it's useful if you want to handle errors more gracefully by using this pattern you can start executing all data fetches at the same time which can lead to Performance gains use a native JavaScript pattern that can be a applied to any library or framework however there is one disadvantage to of using JavaScript pattern uh what happens if a data request is slower than the others so it looks like we've completed chapter 7 awesome great we're moving along all right chapter8 static and dynamic rendering this chapter contains nextjs 14 experimental features that are subject to change the content may be updated as the features are finalized in the previous chapter you fetch data for the dashboard overview page however we briefly discussed two limitations of the current setup the data requests are creating uh an unintentional waterfall and the dashboard is static so any data updates will not be reflected on your application in this chapter we are going to cover what static rendering is and how it can improve your application's performance what dynamic rendering is and when to use it different approaches uh to make your dashboard Dynamic and the limitation of fetching data at request time what is static rendering with static rendering data fetching and rendering happens on the server at build time when you deploy it or during revalidation uh the result can then be distributed and cached stored in the content delivery Network CDN um so here we have the server and then we have our CDN here and then we have our users whenever a user visits your application the cash result result is served there are a couple benefits of static rendering faster websites uh pre-rendered content can be cached this ensures that the user around the around the world can access your website content more quickly and reliably reduce server load because the content is cash your server does not have to dynamically generate content for each user request and SEO pre-rendered content is easier for search engines to crawl to index as the content is already available when the page loads this can lead to improved search engine rankings static rendering is useful for UI with no data the data that is shared across uh users uh such as static blog post or product page it might not be a good fit for a dashboard that has data that can regularly be updated the opposite of static rendering is dynamic rendering quiz time uh why might static rendering not be a good fit for a dashboard uh app because it it's Dynamic data that could be changing because the application will not reflect the latest data changes there we go all right what is dynamic rendering with Dynamic rendering content is rendered on the server for each user request at request time when the user visits the page there are a couple of benefits of dynamic rendering uh real-time data Dynamic rendering allows your application to dis display real-time data or frequently updated data this is ideal for applications where data changes often user specific content it is easier to serve user specific content such as personalized dashboards or user profiles through Dynamic rendering as the data is updated based on user interactions request time information Dynamic rendering allows you to access information that can only be known at request time such as cookies or URL search parameters what kind of information uh can only be known at request time cookies and search URL parameters there we go making the dashboard Dynamic here we go by default versel postgress doesn't set its own caching semantics ah messed that word up uh this allows any framework to set its own static and dynamic Behavior you can use next uh JS API called unstable no store inside the server components or data fetching functions to opt out of static rendering let's add this in your data. TS import unstable no store uh from the next cache and call it at the top of your data fetching functions so here we go we're going to import that in our data. TS file right now so let's go to our data we're going to import that right here Bam Bam stable no store it's in there let's uh get back to this and then in our fetch latest invoices uh fetch Revenue fetch card we're we're going to add that no store uh pretty much everywhere uh okay I got to make sure I add those in all the right places but let's let's just start with fetch Revenue it looks like they're just importing it at the top of the function this one looks like it's in the oh yeah so yeah so they're just in inserting this at the top of each function so let's do that now so we'll do that there do that there so almost there almost there what what we got here I'm just putting them in every single function that's in here and let's see I feel like I can hear my kids just got home and it's going to get really loud in here all right so I think that's right I don't see any errors in the console so note uh unstable no store is an experimental API and may change in the future if you prefer to use stable API in your own projects you can also use segment config option export content Dynamic Force Dynamic here we go simulating a slow data fetch making the dashboard Dynamic is a good first step however there's still one problem we mentioned in the previous chapter what happens if one data request is slower than the others let's simulate a slow data Fetch and see what happens in your data fetch uh data file uncommon the console log set timeout oh so that's already uncommented because I uncommented it earlier by accident so we should be able to see what that looks like right now as we load this there's our I'm assuming that super long pause is why this feels about 3 seconds so there um now open uh the dashboard Tab and uh it takes longer to load you should see the following message in your console I wasn't looking at the console but here let's look at our console let's load that it's the console inside uh vs code because it's uh the backend console like I said I've already had that uncommented so it's probably already been slower than it was supposed to be here we've added in our artificial 3se second delay uh to slow the data fetching the results now the whole page is blocked while the data is being fetched which brings us to a common challenge developers have to solve with Dynamic rendering your application is only as fast as your slowest data fetch nice we completed chapter eight we are halfway done up next is chapter nine all right here we go with chapter nine streaming in the previous chapter you made your dashboard page Dynamic however we discussed how the slow data fetches can impact the performance of your application let's look at how you can improve the user experience when there are slow data requests in this chapter we are going to cover what streaming is and when you might use it how to implement streaming with loading. txx and suspense uh what loading skeletons are what route groups are and when you might might use them and where to place suspense boundaries in your application what is streaming streaming is a data transfer technique that allows you to break down a route into smaller chunks and progressively stream them from your server to the client as they become ready so you got your partial content with loading State here and then suspended content streaming in by streaming you can prevent slow data requests from blocking your whole page this allows the user to see and interact with parts of the page without waiting for all of the data to load before any UI can be shown to the user data fetching and rendering are initiated in parallel so the user can see the UI as it becomes ready this is different from the traditional waterfall approach where data fetching is and rendering are initiated sequentially blocking the UI from rendering until the data is ready we have a is uh fetching on server B is rendering on the server uh HTML rendering on their server C is loading code on the client and D is hydrating so you have the time here and the different components and how they're coming in at those different um levels there so streaming works well with react components model and each component can be considered a chunk all right uh let's take a quiz here what is one advantage of streaming data requests become more secure through the chunk encryption all chunks are rendered only after they are received in full chunks are rendered in parallel reducing overall load times there are two ways to implement streaming in nextjs at the page level with the loading. TSX file and for specific components with suspense let's see how this works streaming a whole page with loading. TSX the app dashboard folder uh create a new uh file called loading. TSX and then add this to it all right so let's go ahead and do that now off to the dashboard close this all up Go app dashboard and then we're going to create a new file called loading. TSX and then in that file we are going to paste that format that a little bit and now we have that all right let's go back to the course all right so we did that and now when we go to the dashboard screen we should see that so let's let's see all right I'm reloading it you can see it's it's kind of loading there and we have the loading indicator or um paragraph tag uh right there so let's see a few things are happening here loading. TSX it's a special nextjs file built on top of suspense it allows you to create loading UI to show as a replacement while the page content loads since sidebar is static it's shown immediately the user can interact with sidebar while the dynamic content is loading the user doesn't have to wait for the page to finish loading before navigating away this is called interruptible navigation congratulations you've just implemented streaming with nextjs uh but can we do more to improve the user experience let's show you how to use a skeleton instead of loading adding loading skeletons a loading skeleton is a simplified version of the UI many web pages use them as placeholder or fallback to indicate to users that cont is loading any UI you embed into loading. jsx TSX uh will be embedded as part of the static file and sent first then the rest of the dynamic content will be streamed in from the server to the client inside your loading. TSX file import a new component called dashboard skeleton all right so I'm just going to I'm just going to go ahead and just copy this whole thing and replace that uh loading file that I have here so now we're importing uh the dashboard skeleton component from U our our project here and then when uh we hit that loading state it will show that dashboard skeleton which you can see here we've got uh that component and we have the skeleton and then it called some card skeletons and then Revenue skeletons and all that so let's go ahead and save loading. TSX go back to our browser and then kick on the loading screen oh look at that that looks nice that that's that's a good user experience definitely all right back to the course now as you see that's exactly what I just did now I went and I reloaded that and showed that loading screen now next is fixing the loading skeleton bug with route groups right now your loading skeleton will apply to the invoices and customer page as well since loading. TSX is at a level higher than invoices page and customers page the in the file system it also applies to those pages we learned that from the routing and and the the way that all that all works since that was at a top level on dashboard uh we can change this with the route groups create a new F folder called overview inside the dashboard folder and then move your loading TSX and Page TSX files into that folder okay so now we're going to create a overview interesting we put parth around it all right so let's do that so in dashboard now we're going to create a new folder with pen over View and then in the overview we're going to move these two into that move that to allow um that to change all the Imports yes I want all those Imports to change all right now let's go page. X I don't know okay so that was changed there I guess I'll save that uh and then let's go back to the tutorial actually let me see if I broke anything looks like that's all still working I guess um definitely got something broken here um I'm going to I'm going to go back to the tutorial and make sure that I'm not doing anything wrong uh okay so I did that and then that structure was correct I just want to make sure I didn't screw anything up I might have screwed something up with the changing the file pass this page. TS is I don't know where this is coming from uh hopefully that didn't screw something up so we got dashboard overview and then we got the page uh. TSX and the overview. TSX here okay and then I know there's something screwy here I'm going to rerun my Dev environment just in in case to make sure that I didn't screw anything up with that and then we're going to go back to here I definitely have an error and I don't know if it changed an underlying import which maybe might have screwed something up but we'll see doesn't look like I've got any errors now all right I think we're good now the loading. TSX file will only appear on your dashboard overview page uh route groups allow you to organize files into logical groups without affecting the URL PA structure when you create a new folder using parentheses the name won't be included in the URL path so dashboard overview page becomes dashboard here using a route group to ensure loading TSX only applies to your dashboard overview page however you can also use route groups to separate your application into sections I marketing routes and uh dashboard routes for your teams and larger applications oh that's pretty interesting all right cool streaming a component so so far you're streaming a whole page but instead you can be more granular and stream specific components using react suspense suspense allows you to the fur rendering parts of your application until some conditions uh is met your data is loaded you can wrap your Dynamic components in suspense and then pass it uh a fallback component to show while the dynamic component loads if you remember the slow data request fetch Revenue this is the request that is slowing down the whole page instead of blocking your page you can use suspense to stream only this component and immediately show the rest of the Page's UI to do so you need to move the data fetch to the component so let's update the code and see what that looks like delete all instances of fetch revenue and it's data from the dashboard overview page okay so going to go ahead and do that so then we'll go back to VSS code all right so let's see here so then where the hell was that fet revenue is in here right I don't know where that came from okay so what did it want us to do remove fetch Revenue right that's what it was telling us to do so I'm going to go ahead and just delete that and see what the next step is then import suspense from react and wrap it around the revenue chart you can pass it a fallback component called Fetch Revenue shart skeleton okay so the skeleton comes from there and then we import suspense from react yeah this is all stuff that I'm not very familiar with at all I know some react but I'm not up to date with the most current react stuff so this is all pretty new to me so let's see let's go back to our vs code um and we're going to do that I said remove the that part to and then Revenue chart like this all this stuff is going to throw an error because I'm no longer importing the fetch Revenue so I don't want to I'm just going to comment that one out nope okay and then what else does it want me to add so then we wrap so we WRA the revenue chart in that which Remy charts already being imported so okay so then we just wrap that with that let's go back not sure why this got changed like that so there's Revenue chart why is it throwing an error down there and here Revenue chart component I am going to be importing the fetch data on that and then I'm just do okay so then I'm just moving it to there okay okay so that makes more sense so then now we go back to vs code we go to let's go to revenue chart component then we're going to have the import here for the fetch revenue and then let me close that that and then where is that Revenue so then I have the I have to define revenue here gos and then we're going to what is that it's going to be uh fetch [Music] revenue revenue and then I screw that up I think this needs to be wrapped in there wait wait it's being passed in here God damn it what am I doing wrong just look at the tutorial quick okay oh yeah because it's no longer being passed in duh that's right so we're no longer passing it in to there so we'll just remove this the formatting is making me not like how this looks so then so basically we're just going to remove that there we go but now I'm still getting an error here so what am I screwing up what am I screwing up oh because I got to make it in a wait duh because it's asynchronous so then okay now that should take care of everything okay so now that handles everything okay so now we should be good with all this so now we should be good all right uh let's go back here and now when you refresh the page you should see the dashboard information almost immediately while a fallback skeleton is shown for Revenue chart let's see if that's what happens so we reload that ah look at that perfect working exactly how we wanted to all right that's great we are we're knocking it out of the park here so practice streaming for latest invoices now it's your turn uh practice what you just learned by streaming by with the latest invoic component move the fetch uh latest invoices down to the page to latest invoices and then wrap the component in suspense boundaries and then the okay so we're basically going to do the same thing but we're going to do it for the latest invoices now so we'll just kind of Follow That same pattern on the page we're going to go here we're going to import the skeleton and and I think it's latest invoice so we'll import the latest invoice skeleton where is the latest invoice here so latest invoice so we're going to do the same thing here we're going to so you know just for the sake of not writing all this stuff out I'm just going to copy and paste all this or actually just just do that and then we're going to move that in here we're we're going to kill kill this format that real quick we're not going to pass in latest invoices of prop anymore in here and we're going to then we're going to change this latest invoice skeleton okay so now it's we're kind of just following the same thing there so then now latest invoices is call is throwing an error because latest invoices is expecting a prop but we're not going to pass in the prop in there anymore we're going to cut this out right here um which is that that's what we're going to use in the um uh latest invoice component so now we go to the latest invoice component and we then um where the hell am I so latest invoice component we're going to we am I here we're not going to take this anymore like that we're going to paste that there and then we're going to take that we don't need that type anymore and then we're going to copy and then we're going to import fetch latest invoices from what's the path just do REM your chart copy uh so it's from from from applib data n damn it wrap that in there I think that should be it I'm missing something there's something I'm missing here what was it that I was doing with the Revenue chart that I'm missing there uh no I'm fetching it and the revenue I think that should be it am I getting any errors here oh that looks good all right so that should be good I think I think that's good I don't think I missed anything let's let's take a look here and we should see the same thing from the invoices now oh all right well let's see hold on so we have the fallback latest invoice skeleton latest invoices and then we're going here we fetch latest invoices which is fetch latest invoices and then we have do we have latest invoices. map into that I think I got everything let me see if I'm missing something maybe I'm not maybe it's just uh am I doing let's see so wait it tell me to do it to move wait a minute why is it having me fetch card data oh no never mind okay that's correct because that's all that should be left now is I should have moved that import into the skeletons there that makes sense but that's all right I'm calling them twice maybe no that shouldn't be creating any problems there okay it looks like I did everything right so I'm not sure if I'm missing something here I should definitely move that into here because that's just that's bad bad call or that's code smell right there because those should just be coming from there not Point into moving that over there so that saves that everything else should be should be good everything else should be should be good uh latest invoices is yeah that should be that should be it all right I'm I'm feeling good about it this is this is right I just uh was expecting to see a load similar to the dashboard stuff but it's just loading faster it's all on the same call oh you know what I think I remember now I think that the dashboard data load has the so okay so that that's what it is so the promise that's fetching Revenue has the uh the 3 minute or the 3 second delay here and that's only on that fetch Revenue it's not in the uh fetch latest invoices if I were to throw in that same set time out here so if I copied this and then throw it into the latest invoices here then I would have that delay but that's why I'm not having the delay because I'm not I don't have that same timeout that makes sense that's why it's not doing that all right makes makes perfect sense it it is working it's just that uh I don't have that same timeout in the data um fetch that's happening there so it's cool it's working uh grouping components great you're almost there now you need to wrap the card components in suspense you can fetch data with each individual card but this could lead to popping effect as the cards load in can be visually jarring for the user so how would you tackle this problem to create more of the staggered effect you can group the cards using a wrapper component means a static sidebar will show first followed by the cards Etc uh in your page uh TSX file delete your card components delete the fetch card data import a new wrapper called card wrapper wrap uh card wrapper in suspense okay so we're going to get we're going to import the card skeleton and we're going to we're going to add this um suspense card skeleton and then we're going to import the card wrapper uh from cards so let's do that go back to vs code uh got got too much going on over here let me just close that stuff so go back up here so we're going to get card components here or card skeleton is it cards card skeleton or card skeleton I think it was cards uh with an S let's double check cards okay because there's a card skeleton too all right so then we're going to uh import that we're going to take this I think I already copied it but let's make sure back to VSS code we're going to take our our whole card component there all [Music] right card wrapper there we're going to import card wrapper from these cards component is that not coming from cards component where the hell does that come from I thought that's where it was coming from card wrapper coming from cards dashboard cards okay well that's confusing all right where so then that is coming from there why is it making me import this here card card wrapper is not coming from dashboard card card s wait a minute so import card wrapper from dashboard cards is because I have that there we go that's all it was okay so that looking better now and I'm guessing we're going to have to go let's just refer to the tutorial I keep I keep getting ahead of myself and trying to do this on my own because I'm I think I know what I need to do afterwards but then it throws me off and it's messing up this uh this video so let's let's go back to where we need to go so yeah so now inside your cards component we're going to do the fetch data and then we're going to we're going to do the uh the same thing we're doing there so basically we're just going to go back to VSS code in here we're going to take this fetch card d data cut that out of here format that save that and then we're going to go for the cards component our cards. TSX here and then we're going to inside of here paste that we're going to need all of that which we are pulling in right here fetch card data cut that from there take that and put it back in here I can just put that there and then that should resolve those errors there let's save everything and then it looks like we've got some stuff that's not commented out here so let's uncomment that why did you do that to me oh because wait where's the uh that should there we go all right so now we have that there and that's saved I think that's all we should do if it works it just it like if if I didn't screw everything up then everything should work and not break which it looks good nothing looks like it broke there um let's see all right refresh the page you see all the cards load at the same time you can use this pattern when you want multiple components to load at the same time deciding where to place your suspense boundaries where you place your suspense boundaries will depend on a few things how you want the user experience uh the page as it streams uh what content you want to prioritize if the components rely on data fetching those are the three reasons take a look at your dashboard page is there anything you would have done differently don't worry there isn't a right answer you could stream the whole page like we did with loading TSX but it may lead to longer load times if one of the components has a slower slower data fetch you could stream every component individually but that may lead to UI popping into the screen and you could also create a staggering effect by streaming the page in sections but you'll need to create wrapper components where you place your suspense boundaries will vary depending on your app application in general it's good practice to move your data fetches down to the components that needed and then wrap those components in suspense but there is nothing wrong with streaming the sections or the whole page if that's what the application needs don't be afraid to experiment with suspense and see what works best for you it's a powerful API that can help you create more delightful user experiences cool in general what is consider good practice when working with suspense and data fetching move data fetches up to the parent component avoid using suspense for data fetching move data fetches down to the components that need it use suspense only for error boundaries I'm going to go with C on that one yay all right looking ahead streaming and server components Give us new ways to handle data fetching and loading States ultimately with the goal of improving the end user experience in the next chapter you'll learn about partial pre-rendering a new nextjs compiler optimization built with streaming in mind based on your suspense Bal boundaries cool we just completed chapter 9 on the 10 we're almost there guys all right chapter 10 partial pre-rendering optional partial pre-rendering is an experimental feature introduced in nextjs 14 the content on this page may be updated as the feature progresses in stability stability stabil I can't read oh my eyes hurt oh this has been taking so much longer than I expected it to partial pre-rendering is an experiment Al feature introduced in next js14 the content of this page may be updated as the feature progresses in stability you may want to skip this chapter if you prefer to not use experimental features this chapter is not required to complete the course uh we're going to do it we're going to do it because I I want to do all the chapters even if it's optional even though this is experimental it might become a thing that they use permanently in the future and why not we're doing it let's go in this chapter here are the topics will cover what is partial pre-rendering and how partial pre-rendering Works combining static and dynamic content currently if you call a dynamic function inside your route uh no store cookies Etc your whole route becomes Dynamic this aligns with how most web apps are built today you either choose between static and dynamic rendering for your entire application or specific routes however most routes are not fully static or dynamic you may have a route that has both static and dynamic content for example let's say you have a social media feed the post would be static but the likes for the Post would be dynamic or an e-commerce site where the product details are static but the user's cart is dynamic going back to your dashboard page what components would you consider static versus Dynamic once you're ready click on the button below to see how we would split the dashboard route all right let's let's take a look let's let's take a look let's just look at the application um and not not the code so I would say if I'm looking at this right the recent Revenue uh seems to be based off of your your month right so I don't know if that's going to update dynamically but I can see how latest invoices would be uh Dynamic so the dashboard could be static um because if that's updating at the end of the very month then it probably doesn't need to be updated uh dynamically and it could be static because it's based off of the previous month's Revenue but latest invoices could definitely be dynamic because those can come in as um new invoices come in and also uh I think that some of this information up here uh can definitely be dynamic and not static so let's see uh let's reveal the solution God damn it all right so apparently the revenue is also Dynamic so I you know I was looking at the month there I was thinking that maybe uh maybe that that that could have been uh not loading in real time but we see that the only thing that is uh static is the sidebar uh the side naab component uh doesn't rely on data and is not personalized to the user so it can be static the components in the page rely on data that changes often and will be personalized to the user and they can be dynamic what is partial pre-rendering in NEX js14 there is a preview of a new compiler optimization called partial pre-rendering partial pre-rendering is an experimental feature that allows you to render a route with a static loading shell while keep keeping some parts dynamic in other words you can isolate the dynamic parts of a route for example you have your your uh static stuff here is uh in the purple and then you have your Dynamic stuff in the blue so you got your recommended down there and your cart up here that's Dynamic and everything else is uh static like the product information in the naad bar when a user visits a route a static route shell is served this makes the initial load fast this shell leaves holes where dynamic content can load in async the async holes is loaded in parallel and reducing the overall load time of the page this is different from how your application behaves today where entire routes are either fully static or dynamic let's take a quiz uh what are the holes in the context of partial pre-rendering it's locations where JavaScript is disabled location where Dynamic content will load asynchronously locations where third party scripts are loaded we know that's B cuz we just literally read that so how does partial pre-rendering work partial pre-rendering leverages reacts concurrent apis and uses suspense to defer to defer rendering parts of your application until some condition is met like data being loaded the fallback is embedded into the initial static file along with other static content at build time during revalidation the static parts of the route are pre-rendered and the rest of this is postponed until the user request to Route it's worth noting that wrapping a component in suspense doesn't make that component itself Dynamic remember you used unstable no store to achieve this Behavior but rather suspense is used as a boundary between the static and dynamic parts of the route the great thing about partial pre-rendering is that you don't need to change your code to use it as long as you're using suspense to wrap the dynamic parts of your route nextjs will know which parts of your route are static and which are Dynamic that's that's that's pretty cool that's uh it's a really cool feature I'm really liking this nextjs stuff it's it sounds as good as a lot of people made it out to be to recap you've done a few things to optimize the data fetching in your application you've created a database with the same region of your application code to reduce latency between your server and database uh you fetch data on the server with react server components this allowed you to keep expensive data fetches and Logic on the Ser on the server reduce uh reduces client side JavaScript bundle and prevents your database secets from being exposed to the client we've used SQL to only fetch data you needed uh reducing the amount of data transferred for each request and the amount of JavaScript needed to transform the data in memory parallelized parallelized parallelized yeah that's a tough one for me uh data fetching with JavaScript where you made sense to do so uh implemented streaming to prevent slow data requests from blocking your whole page and now it allows the user user to start interacting with the uui without waiting for everything to load and you've moved fetching down to the components that need it thus isolating parts of your routes that should be dynamic uh in preparation for partial pre-rendering in the next chapter we'll look at two common patterns you might need to implement when data uh when fetching data like search and pagination chapter 10 is complete all right on the chapter 11 all right we are now in chapter 11 and chapter 11 is adding search imp pagination uh in the previous chapter you improved your dashboard's initial loading performance with streaming now let's move on to the invoices page and learn how to add search Imp pagination in this chapter we'll cover topics uh learn how to use nextjs apis search prams use path name and use router Implement search imagination using URL search prams all right here we go starting code inside your dashboard invoices page paste the following code I'm just going to copy that whole [Music] thing all right so let's go to our invoices page um where we at invoices page here we're going to just go ahead and paste that whole thing and save that and then we're going to go back here to the tutorial and see what this code is doing doing all right spend some time familiarizing yourself with the page and the component you'll be working with the search allows you to use the search for specific invoices pation allows you to navigate between Pages for invoices and the table uh displays the invoices your search functionality will span the client and the server when the user searches for an invoice on the client the URL prams will be updated uh data will be fetched on the server and the table will render the server with new data data that a little bit all these components that they built for us already which is uh you know a lot of the work is already done for us there and yes all right so we have your create invoice here all right all right see seems clear enough so why use URL search prams as mentioned above you'll be using URL search prams to manage the search state this pattern may be new if you're used to doing it with client side state there are a couple of benefit of implementing search with URL prams bookmarkable and sharable URLs since the search prams are in the URL a user can bookmark the current state of the application including their search queries and filters for future referencing or sharing server side rendering an initial load URL prams can be directly consumed on the server to render the initial State making it easier to handle server rendering analytics and tracking having search queries and filters directly in the URL make makes it easy for you uh to track user Behavior without requiring additional client side logic logic adding the search functionality there are three nextjs client hooks that you'll use to implement the search functionality use search prams allows you to access the parameter of the current URL for example the search params for this URL is dashboard invoice then you have page one and you have query pending then we'll look at this and it's we're looking for page one and query pending use path name lets you read the current URL path name for example the route is dashboard SL invoices use path name would return dashboard SL invoices use router enables navigation between routes within client components programmatically there are multiple methods you can use here's a quick overview of the implementation steps capture the user's input update the URL with the search prams keep the URL in sync in the input field update the table to reflect the search query so Step One is capture the user's input go to the search component uh search. TSX and you'll notice use client this is a client component which means that you can use event listeners and hooks and then you have input which is the search input and then uh create a new search handle function or handle search function create a new handle search function and add onchange listener to the input onchange will invoke handle search whenever the input value changes all right so let's go to our search function we're going to do this handle search that'll fire on change so let's go to our VSS code uh let me see if I can just find search TSX I'm not going to look for it in the uh folder structure there we got our used client here and and then we're going to we're going to have all of this stuff here and there's our function that we'll be adding there for handle search and then we're going to add that to the input that we'll do on change right so we're going to go on change and then let that auto complete and then we'll handle search and [Music] then um and then the where's the value that we're going to be passing in there CU we got to pass in a Pam so getting some let me see if this has anything here so we're going to call the event okay so it wants us to pass in a function there so just pass in a function we'll pass an event and what is it is it like event Target what was it event target. value I think that's it yeah that should be it event target. value okay so then we'll do that and that looks good no errors there uh test is working correctly by opening your console and then you should see it log it all right so let's go back there let's go here we should see the invoices page now we see our our search here and we have our console open so let's just go blah there you go you can see it's all all right so now we're on our invoices page and we can see that when we enter stuff in this our console's being updated every time we change and enter a new value and if I delete it you can see it all deletes so that's working there awesome all right back to the tutorial update the URL with the search parameters so import the use search parameters Hook from next navigation and assign it to a variable okay so in that same search uh file we're going to import this from next navigation and we're going to um set it as a variable and do all that good stuff so let's do that real quick uh where are we so search we're going to import that here and then copy that and then we were going to do that and then that and then what was it uh [Music] thens is that a wait not that's not a wait all right so there we got that let's see all right so we did that part inside handle search create a new uh URL search prams instance using the new search params variables so here so we're going to create the search parameters using this Constructor okay so that's that's simple enough so I should have just copied that I'm going to I'm going to copy that no point in typing all this stuff so let's copy that go back to the VSS code and then in this here we're going to just replace that and then oh wait a minute what did I screw up oh what am I doing wrong here oh because I'm I'm not calling that search parameters in the function okay duh okay all right there we go had that nested incorrectly and it was not in scope there all right so then that should do that and let's see what else it wants us to do so then now is the web API provides utility methods for manipulating the URL query parameters instead of creating a complex string literal you can use it to get the prams like the page okay next set the pram string based on the user's input uh if the input is empty you want it to delete okay so here we have so we're taking in the term if the term is uh prams let's set query is term and else is delete query okay so all right easy enough there now you have the query string you can use nextjs use router and use path name hooks to update the URL import use router and use path name from navigation and then replace the method me from use router inside a handle search use the replace method okay so so we're going to add that there and then what does it want us to do here so we're going to create these two variables there we're going to add these two variables here and then what's the next thing we're going to do we're going to replace okay so we're doing this template literal [Music] here okay all right so replace the path name quy all right that looks good all right so here's a breakdown of what's Happening uh the path name is uh the current path in your case dashboard invoices as the URL types into the search bar prams to string translates this input into a URL friendly format the replace path name uh prams to string command updates the URL with the user search data for example dashboard invoice query equals Lee if the users search for Lee the URL is updated without reloading the page thanks to nextjs client side navigation which you learn which you learned about in the chapter of navigating between pages keep the URL and input in sync to ensure that the input field is in sync with the URL and will be populated uh when sharing you can pass the default value to input by uh by reading from search prams default value we put this into our input where is our input okay save that there and pretty sure we're going to have to check to make sure everything's working default value versus value uh default value versus value controlled versus uncontrolled if you're using state to manage the value of an input you use the value attribute to make a controlled component this means react with manage the input State however since you're not using State you can use default value this means the native input will manage its own State this is okay since you're saving the search query uh to the URL instead of State all right so updating the table finally you'll need to update the table component to reflect the search query navigate back to the invoice page uh t uh page components accept a prop called search pram so you can pass the current URL parameters to the table component where we at we are on the invoices page here so we're going to update this to take in search prams as a prop and then these will be optional and then we'll do query search prams okay so then let's just go add all this stuff to the invoices page now so invoices where is it yeah I'm look I'm looking at the wrong invoices there's invoices components there all right so here we are so we want to add that here I I don't even remember what I'm doing cuz I got lost there so we're going to add that to this uh I don't remember how I copied that so I'm just going to replace okay there we go that's what I was doing that's what I wanted to do all right so now let's go back to the tutorial see what the hell I got to do next all right so we added that and then we're just going to add the suspense and that's going to have a key of the CER current page and then the fall back is going to be the skeleton and then the table is taken in it's query and then the current pay okay so we'll just add that real quick to the table component there I don't even know if it's there so it's under which div the placeholder search invoices okay just got to see where I need to put this oh here it is it's already there I just got to uncomment it wonderful they did most of the work for me all right so let's save that now all of this should just work like magic if all the code is correct so let's hope that I didn't screw anything up and you can see as I am updating that you can see how it's updating up here the query of Lee and I can probably even type in Lee if I if I do that I bit you it'll it'll work as well but there you go you can see that this is uh now working and we have that working as we want it to be working which is beautiful that's a beautiful thing all right if you navigate to the table component you'll see that the two props query and current page are passed into the fetch filtered invoices function which is returning the invoices that matches the query with these changes in place go ahead and test it out if you search uh for a term you'll update the URL which will send a new request to the server the data will then be fetched and only the invoices that match your query would be returned when you use the use search prams hook versus the search pram prop you might have noticed that you use two different ways to extract the search prams whether you use one or the other depends on whether you're working on the client or the server search is a client component so you can use uh search prams hook to access the prams from the client table is a server component that fetches data on its own so you can pass the search params prop from the page component there as a general rule if you want to read the prams from the client use the uh use the use search prams hook hook to avoid having it go back to the server for Best Practices uh debouncing congratulations you've implemented search with nextjs but there's something that you can do to optimize it inside your handle search function add the following console log all right let's let's do that where's our handle search and then wanted right there searching term okay and what else does it want us to do then type email into your search and check the Deb tools to see what's happening all right so we got Deb tools open okay yeah I can I can see that it's it's doing that okay yeah you're updating the URL every keystroke and therefore querying your database on every keystroke this isn't a problem as your application is small but imagine if your application had thousands of users each sending a new request to your database on each keystroke debouncing is a program the practice limit rates which the function can fire in your case you only want to query the database when the user has stopped typing how debouncing Works trigger event when an event that should be debounced like a keystroke in a search box occurs a timer starts wait if a new event occurs before the timer expires the timer is reset execution if the timer reaches the end of its Countdown the debounce function is executed you can Implement debouncing in a few ways including manually creating your own debounce function to keep things simple we'll use a library called used debounce so we got to import this uh Library real quick all right we got that in there what does it want us to do next all right so then we're going to go to our search component and we're going to import that there all right so where's our search component we're still in there and we're going to import use the bounce here and then we're going to where we going to use that here and then we are going [Music] to just add a new line there's there's nothing there the function will wrap the contents of the handle search and only run the code after a s a specific time has occurred once now start typing your search again and see your Dev tools is okay well oh so now we're using okay so there it is they it's weird because they didn't really highlight the right code there but I see what they're doing all right so we're going to add that to the handle search where's where's this at handle search wait a minute what was the syntax there handle search equals okay so now I got to all right so I got to change that into an arrow function you guys are making me work actually I'm just going to I'm just going to copy this there we go screw that up I broke something term Arrow function that closes that God damn it oh I got to set the timer there so there we go that's what I'm missing okay so now let's see what that does when we fire that let's look at our console ah ah all right yeah so there's that delay down there at the bottom if you saw it down here as I type it's not doing it until I stop and then it has that 3 millisecond delay cool that's awesome that's that's really neat all right this function will wrap the contents of handle search and will only run the code after a specific time has occurred the three 300 milliseconds or now type your search bar again open your console we already did that and by debouncing you can reduce the number of request that you're sent to your database does saving resources that's really nice I like that uh what problem does debal need solve in the uh search feature it helps prevent new uh database query on every key stroke next we are adding pagination after introducing the search feature you'll notice that the table displays only six invoices at a time this is because the fetch filtered invoices function in data. TS returns a maximum of six invoices per page adding P page name pagination allows users to navigate through the different pages to view all invoices let's see how you can Implement page ination using URL prams just like you did with search navigate to the page ination component and you'll notice that the client component that it's a client component and you don't want to fetch data on the client as you would expose your database Secrets remember you're not using API layer instead you can fetch the data on the server and pass it to the components as a prop uh in the dashboard invoices page import a new function called Fetch invoices page and pass the query from the Search print prams as an argument all right so we're going to we're going to go ahead and copy this we're going to go to the invoices page now where is invoices page Ah that's the wrong invoice because I'm in the components invoices page there we go so we're going to pass that looks like I'm already importing page ination there so we're already okay fetch the invoices page there let's go back to this and then see what we're going to do here inside the page component we're going to put that asynchronous method in there right underneath here we're going to put that method right here and let's see what else it wants us to do fetch invoices page Returns the total number of pages based on the search query for example if there are 12 invoices that match the search query each page displays six invoices and the total number of of pages would be two next pass the total Pages prop into the pagination component so it looks like that's right there I think that might be commented out right now so here it is all right so I just uncommented that your application will break temporarily as you haven't implemented the page ination logic yet let's do that now navigate to the pagination component import the use path name and use search pram Hooks and we'll use this to get the current page and set the new page so we're going to import that from next navigation into the pagination component there's that and then let's see what the next step is and then we are going to add these variables here I'm just going to say that's this I don't know I don't I don't I don't think it uh I'm so confused it says to to comment that when you get to this point but I'm not totally sure if we are at this point or not so I'll wait for that let's go back to the tutorial and see what else I need to do next create a new function inside the component uh called create page URL similar to the search you'll use the URL search prams to get the new page number and path name to create that all right so we're going to be creating a page URL um function here which takes a page number that can be a number or string and then we use the search prams there which are being passed in from where where search param coming from search param right here use search prams and then we set the page to the number of the string and return the path name with the prams okay so let's copy that go back to vs code and then we're going to paste that there that's looking good so far let's go back to the tutorial here's a breakdown here's a breakdown of what's Happening create page URL creates an instance of the current search parameters then it updates the page parameters with the provided page number finally it constructs the full URL using the path name and updated search params the rest of the page ination component deals with the styling of different states first last active disabled we won't go into detail for this course but feel free to look through the code to see what create page URL uh where create page URL is being called finally when the user types in a new search query you want to reset the page number to one you can do this by updating the handle search function in your search component so now we are in the search component and then we are going to be doing set params to page one so we're setting that in that component there so let's go back to the search component uh which is right here and where was it doing that I wanted that to be done here so right was that is that here rams. set page one when you're searching yep I think that's what you wanted to do because you got your pams and then you set page to one and that's that's I think that's what we want so let's double check the tutorial yeah so this is looking good congratulations you've just implemented search and pagination into the to summarize hold on let's go make sure it's working right so so here let's let's just reload this page here oh would you stop it let's reload this now hold on hold on hold on hold on what's this error let's make sure that that everything's looking good here just for the sake of being safe since I've updated so many things recently I'm going to just kill that and reload this just to make sure that something funky is not happening CU I've been I've been bit in the butt too many times by something like that before so we do have a problem here though hydration failed because the initial UI does not match what was rendered on the server I was getting an error but I think it was because I had some weird parameters in there um in the URL I cleared that and the eror is gone that works all right so I mean that looks good but I'm not seeing I'm not seeing my page ination here people where where is it what what am I missing I'm missing something missing something I don't think I'm at this point yet because I'm getting an error when I'm commenting that oh well well would you look at that maybe maybe I need to actually comment out the damn component itself I don't know how many times this has happened to me but so this is funny so I'm getting an error I don't know if they updated this course or something so where's current page so oh because this needs to be called there there we go was trying to call it before it was declared okay so that should fix that all right so we're good now we're good now this should be working let's double check hey all right all right nice nice nice all right that's working great beautiful congratulations you've just implemented search imp pagination using URL prams and nextjs apis to summarize in this chapter you've handled search imp pagination with URL search parameters instead of client State you've fetched data on the server and you're you're using the used router Router hook for smoother client side transitions these patterns are different from what you may have used when working with client side react but hopefully you now better understand the benefits of using URL search progams and lifting this state into the server hey chapter 11's done nice on the chapter 12 all right so we are on chapter 12 we're getting real close to finishing this I'm actually looking forward to finishing this because this is actually taken me a lot longer than I expected it to but hey I'm learning I'm learning a lot I hope you guys are learning too if you're enjoying this drop a comment down below let me know what you think of this course I'm really liking it so far and and I I'm liking nextjs I think it's pretty pretty damn cool chapter 12 mutating data in the previous chapter you implemented search imp pagination using URL search prams and nextjs apis let's continue working on the invoices Page by adding the abil ability to create update and delete invoices yeah we getting into a little bit of crud here all right in this chapter here are the topics we'll cover what react server actions are and how to use them to mutate data how to work with forms and server components best practices for working with Native form data object including type validation how to revalidate the client cache using the revalidate path API how to create Dynamic route segments with specific IDs how to use reacts use form status hook for optimistic updates and there's a lot of good stuff here so what are server actions react server actions allow you to run asynchronous code directly on the server they eliminate the need to create API endpoints to mutate your data instead you write asynchronous functions that execute on the server and can be invoked from the client or the server components security is a top priority for web applications as they can be vulnerable to various threats this is where server actions come in they offer an effective security solution protecting against different types of attacks securing your data and ensuring authorized access server actions achieve this through techniques like post request encrypted closures script input checks error message hashing and host restrictions all working together to significantly enhance your apps safety using forms with server actions in react you can use the action attribute in the form element to invoke actions the action will automatically receive native form data object containing the captured data for example in This Server component here you have your asynchronous function uh which creates and it takes in uh form data type there and you have your used server right here and then your logic to mutate the data and then here you call your create on the form uh when the form action happens all right an advantage of invoking a server action within a server component is Progressive enhancement uh forms work even if JavaScript is disabled on the client that is pretty cool all right so nextjs with server actions server actions are also deeply integrated into the nextjs caching uh when a form is submitted through a server action not only can you use the action to mutate data but you can also revalidate the associated cache using apis like revalidate path and revalidate tag all it's time for a quiz what's one benefit of using the server action improves a SEO Progressive enhancement faster web apps data encryption oh I got it wrong that's my first one uh Progressive enhancement is what there we go okay I got one wrong Let's uh see how it works together creating an invoice here are the steps you'll take to create a new invoice create a form to capture your user's input create a server action to invoke it from the form inside your server action extract the data from the form data object validate and prepare the data to be inserted into your database insert the data and handle any errors and revalidate cache and redirect the user back to the invoices page so first we're going to create a new route and form and we're going to do this inside the invoices folder and we're going to add a new route called create with a page. TSX file all right let's get to it so we're going to go into our app dashboard invoice and in here we're going to create a new folder called create and in that folder we're going to create a new page or a new file I'm sorry named page. TSX and then in that TSX file we are going to do what here here you'll be using the route to create a new invoice inside your page uh paste the following code and spend some time studying it I'm just going to paste it and then we can look at it in vs code so all right so let's paste that in there this looks fairly simple let me format it a little bit all right so here what do we got here all right so this is uh the main uh div here we've got some breadcrumbs that are going to probably display at the top there that show the uh paths that we're on there and then we have a form that um is going to be here and this is just calling the form component and the breadcrumbs component here all right that's fairly straightforward here in this we got an an asynchronous uh function here being called for customers which is going to fetch the customers all right that's pretty straightforward let's go back to the course now your page is a server component that fetches customers it passes in the form component to save time we've already created the form component for you navigate to the form component and you'll see the form it has two select drop down elements customers and status has one input element for the amount and type of number and it has one uh button type uh submit so if we go to this path here we we can see that now so let's let's go there real quick and we're going to go um it was invoices right and then it was create and then we should be able to see this form now here we go so we got the two drop downs which have uh the the customers that are being called from the the database and populated by by that um call there we have an amount and then we have statuses that we can check there which is nice looks just like how it should and now we're going to create a server action here now we will create our server action and this is going to be called when the form is submitted so navigate to your lib directory and create a new file called actions. TS at the top of this file add the react use server directive okay so app lib and we're going to create actions and we're going to uh add use server to it okay easy enough so let's go back to vs code we're going to go to our our lib we're going to create a new file what was it called uh actions let's try that again new file actions. TS and and then we're just going to use the use server use server uh directive there and I think that's I mean that's that's it that's pretty straightforward there format that and let's go back to the tutorial now all right so that looks good by adding the Ed server you marked your uh you marked all the exported functions with the file as server function fun these server functions can be imported into the client and server components making them extremely versatile you can also write server actions directly inside server components by adding new server inside the action but for this course we'll keep them all organized in a separate file separation of concerns right that's what I'm talking about uh in your actions file create a new async function that accepts form data so we're going to create this empty function here that takes in some form data and we're just going to slap that in there let's slap it in there on SLAP it right right here slap all right um all right easy peasy let's go back to the tutorial see what else is next then in your form component import the create invoice of uh from your actions. TS and uh add the action attribute to the form so we're just going to be pulling in that create invoice there in that uh create form wait a minute do I already have that component I hope they already have that component for me in your form component I'm confused because this is named create form I I don't I don't like that so whatever we'll find it uh form let's let's look for form see so it's in the create form so in this component we are going to import that create uh invoice there and then what are we going to what are we going to do with that we're going to we're going to add the form uh action to the form uh and we're going to create invoice on the form okay so where's our form here nice and easy boom simple simple let's let's go back here uh good to know in HTML you'd pass a URL to the action attribute this URL would be the destination where your form data should be submitted usually an API endpoint however in react the action attribute is considered a special prop meaning react Builds on top of it to allow actions to be invoked rather than calling an API explicitly you can pass a function into action uh okay behind the scenes server actions create a post API endpoint and this is why you don't need to create API endpoints manually when using server acction that's pretty cool it's kind of just smart automa magic for you so you don't have to do it um three we're going to extract the data from form data back in your actions TS file you'll need to extract the values of your form data there are a couple of methods that you can use for this example let's use the get name Method All right so this is our create invoice all right and we're just going to add all this to it and uh we got our raw raw form data so we're going to from form data that's being passed into this create invoice we're going to get the customer ID uh for customer ID we're going to get the amount for amount we're going to get the status for status and then we're going to console log all of that to make sure that it works if you're working with forms in many fields you may want to consider using entries method and JavaScript object form entries for example cons raw object form entries for okay so let's just go ahead and do this copy that we're going to go back to that um create invoice or is it or damn it now now I've got I've got too many too many things going on here ah I'm lost where's all my crap actions there we go okay so now we're just going to replace that with this and then save that and now you should see this stuff console log with this git if I actually do everything right so wait a minute but no but that's not the right form there's the other form you know what I'm not I'm not going to let me follow the tutorial before I get ahead of myself again and get lost because I did that earlier trying to be all smart and stuff so let's go back to the tutorial all right uh here we go to check everything is connected correctly go uh and try out the form after submitting you should see the data that you just entered uh logged in the terminal oh that's because I'm not am I wait a minute that's the right that's the right right place here let's just it's supposed to take let's just do 100 and then we'll select paid I'm not getting anything oh wait it's a server action so duh so it's it's a server action I'm not going to see it in the client side but here is the console log of what I just entered um as you can see it's right there because is logging on the server side not the client side don't make that mistake like I just did all right all right so back to the tutorial see that's working now validate and prepare the data before sending the form data to your database you want to ensure that it is correct format and has the correct types if you remember from earlier in this course your invoices table uh expects data from the following format that's right that's right so that's our invoice uh type there so we want an ID we need a customer ID we got an amount we got a status and we have a string for date all right uh so far you only have a customer ID amount and status from the form type validation and cerion it's important to validate that the data from your form aligns with the expected types in your database for instance if you add a console log inside your action this type of raw form amount you'll notice that the type of uh string is not a number and this is because input elements of type number actually return a string not a number thank you JavaScript um to handle the type validations you have a few options while you can manually validate types using the type validation Library you can save some time and effort for example we'll use Zod a typescript first validation library that can simplify this task for you all right cool let's check out Zod uh in your actions file import Zod and Define a schema that matches the shape of your form object this schema will validate the form data being uh before saving it to the database all right so let's import this Zod and this schema I'm just going to copy all of this yep we're going to copy all that we're going to go back here we're just going to just paste that right there oh yeah that looks good all right that looks good let's go back to the tutorial there the amount field is uh specifically set to coh change from the string to a number all that's cool all right and then you can pass your raw form data to new invoice and validate types okay so now inside of that create invoice I am going to create parse this here what did I do wrong wait a minute what did I screw up I screwed something up no I didn't screw that up but let see what I did because that doesn't exist anymore [Music] that and then all right so that looks better now let's go back to this so storing values in sense it's usually good practice to store monetary values in sense in your database to eliminate JavaScript floating Point errors and ensuring greater accuracy let's convert the amounts into cents so we G add that there should go right here all right now what's next all right create creating new dates so now we're going to create a date and we're going to do all this good stuff to uh massage that date into a format that we want all right so let's go in here and then we're going to take that date we're going to do that now let's go back and see what else it wants us to do inserting your date into the database so now we're going to import SQL from versel postgress here and then we're going to um do an await SQL here and we're going to insert all this stuff there that we just uh got from the form here all right sweet so let's go back there let's uh where am I I'm lost here we're gonna import that there and then let me go copy the rest of this this uh query and then we're going to do there where did I want that I wanted that here we're just going to do that and clean that up a little bit all right that's looking good that's looking good let's uh let's go back to the tutorial see what else I need here right now we are not handling any errors well do it in the next chapter for now let's move on to the next step revalidate and redirect nextjs has client side routing cache this uh that stores the route segments in the user's browser for a time along with prefetching this cache ensures that users can quickly navigate between routes while reducing the number of requests made to the server since you are uploading the data displayed uh in the invoices route you want to clear the cach and trigger a new request to the server you can do this with revalid path function from nextjs okay so we're going to import that at the top there all right there's a lot of Auto Magic in nextjs which is nice so something breaks uh let's see and then we're going to revalidate path down there going save that that looks good is that where I wanted it yep okay so that looks good once the database has been updated the dashboard invoices path will be revalidated and the fresh data will be fetched from the server at this point you also want to redirect the user back to the dashboard invoices page and to do this we can do the redirect function from nextjs all right so now we're going to redirect so after they submit the form we revalidate the path and then we redirect them all right so let's uh let's go in here let's insert this from navigate it's the same thing we just do that redirect there and that's where we're taking them afterwards so that looks good too what's the next step congratulations you've just implemented your first server action yeah nice uh test it out by adding a new invoice everything is working correctly you should be redirected to the dashboard invoices route on submission and you should see the new invoice at the top of the table okay so let's go in here let's enter this you know what let me just reload it real quick let's select a customer we're going to go with Lee Robinson there he's familiar we're going to make it all threes and you know what leaves a standup guy I'm sure he paid so let's create that invoice should redirect us and there it is right at the top of the page with our date in a nice readable format we have ourl and we have Lee Robinson there perfect everything's working great we just did our first server action hooray what's the next step updating an invoice the updating invoice form is similar to the create invoice form except you'll need to pass the invoice ID to update the record in your database let's see how you can get and pass the invoice ID these are the steps you'll take to update an invoice create a new Dynamic route segment with the invoice ID read the invoice ID from the page prams fetch the specific invoice from your database pre-populate the form with the invoice data update the invoice data in your database so step one is going to be create a dynamic route segment with the invoice ID nextjs allows you to create Dynamic route segments when you don't know the exact segment name and want to create routes Based on data this could be blog post titles project Pages Etc you can create Dynamic route segments by wrapping a folder's name in square brackets for example ID post or slug in your invoices folder create a new Dynamic route called ID and then a new route called edit with a page. TSX file and your page your file structure should look like this so invoices we're going to have the square the brackets around ID and then we're going to have edit and a page there okay so let's go to invoices new folder do ID and then in there we're going to create a new folder edit and in there we're going to create a new file do TSX I believe that's what it should look like let's just make sure that I did that right yep so we have ID we have edit and we have page all right so that looks good that looks good in your table component notice that there is an update invoice button that receives the invoices ID from the table records so we have that update invoice uh here I'm I'm going to go make sure it's there so this is in my invoices table so here here's that that's there all right looks good looks good all right so that's there let's go back to this navigate to your update invoice component and update the href uh of the link to accept an ID prop you can use template literals to link the dynamic route segments okay so we'll go to that and this is uh invoices buttons of components so which is it's right here I see it I'm not going to search it because I see it and then we are going to do a template literal there and then we're passing the ID right here there's that prop there all right easy peasy lemon squeezy read the invoice ID from the page prams uh back on your page component paste the following code in here okay so now we're going to that new uh page component that I created inside side ID edit and we're just going to copy all of this stuff it's a lot of stuff so so here's that empty file paste that there I can see I have some errors already that's lovely I'm just going to save that and blow up the compiler and throw all those errors and it says notice how it's similar to your create invoice page except it Imports a different form from the edit form TSX file this form should be pre-populated with a default value for a customer's name invoice amount and status to pre-populate the form Fields you need to fetch the specific invoice using ID in addition to search prams uh page components also accept a prop called prams which you can use to access the ID update your page component to receive this prop and that must be where those errors were coming from so now we're going to update the page component with this mhm just just re just you know take that there there we go I'm still getting some errors down there from from that other stuff but that's okay let's keep let's keep moving through the uh tutorial I'm sure those errors will go away and here here we go we got invoice and stuff and that's where that's going to come in so then uh on step three to fetch the specific invoice we're going to import a new function called Fetch invoice by ID and pass it an ID as an argument and then we're going to import uh fetch customers to fetch the customer name from the dropdown you can use promise all to fetch both the invoice and the customers in parallel so we're going to take those fetch methods that we had that we were using on the dashboard and we're going to use those in our edit oh well we already hold on so let me just replace this then all right so there's that and then what was the next step that they want us to do so there's that I just pasted that here uh and then the next step that they want us to do is create this variable fetching that and doing the promise all for invoic and customers all right great this is coming along real nicely all right great now test everything is wired correctly visit the dashboard invoices and click on the pencil to edit an invoice all right so let's go to our dashboard we're on our invoices page I just did a refresh real quick and we'll go ahead and edit this invoice maybe I I charged I charged Lee a little too much so we're going to we're going to just make that even hundo but he didn't pay so we're going to change that there and then we're going to edit that invoice and now this should reach direct us no cuz this is a different this isn't create this is edit so we don't have the redirect in place or anything like that and the amount is the same so it fetched the amount so nothing updated but we are on this page and everything is here so what's the next step yeah because everything is populated so that that whole point was to make sure that it was actually fetching the data there so it should be updated um as follows uh the URL should also be updated yes so the URL does have their unique ID in in there and it has the customer ID and all of that stuff beautiful okay so that all worked that all worked nice just how we wanted it to we use uu IDs instead of uh incrementing keys this makes the URL longer however Goods eliminate the risk of ID collision and are globally unique and reduce the risk of enumeration attacks yep uh pass the ID to the server action lastly you want to pass the ID to the server action so you can update the right record in your database you cannot pass the ID as an argument you can not pass the ID as an argument like so instead you can pass the ID to the server action using JS bind this will ensure that any values passed into the server action are encoded so in form edit we are going to import this update invoice from actions that that we have here so we're going to form edit where the hell is uh where is that this is this it God damn it invoices edit form okay so yeah that's so we're in here I'm going to import this update invoice why why are you giving me is it is that not the path wait a minute what is what's going on here so we are invoices edit form. TSX is that not the right am I not in the right place here so this is invoices edit form. TSX okay well what what's going on oh you guys are throwing an error for it not being used that doesn't make sense has no export member updated okay so why where where's the export oh because I haven't created it yet yeah that makes a lot of sense okay well let's get back to the tutorial again getting ahead of myself I'm going to have to create that but here let's just uh do what it's telling us to do here so I'm going to add this to that see now now see now I'm I'm lost here because because I'm because I'm getting ahead of myself I'm doing stuff you know that I shouldn't be doing so that's that we import that there or we create that there and use that bind there and then what are we doing here and then we're just updating the form action for the edit form there where's that form we're just going to add that here and that's all good except I don't have that method yet because that has not been created yet and and I know it's throwing an error but that's okay because I'm sure that's going to be the next step yep here we go so uh using a hidden input uh field in your form also works uh input hidden name uh value invoice ID however the values will appear in full text in the HTML sorts which is not ideal since sensitive data is like IDs yeah so you don't want to do that then your actions we're going to add this update invoice which is going to use Zod so up so we're going to create this inside form actions so this is going to be pretty much everything like the create was you have you have it updating all the invoice here um you're getting all that and then you update instead of create on the SQL query and you kind of pass in all that same stuff then you revalidate and then you redirect so it's it's pretty much doing the same thing except we were updating instead of creating and I'm just going to go and update that now so where was I in our actions I'm going to import this oh there you go and then I am going to create the update here copy that and then go back here and then create update there and then now that should be all happy and it should work and I shouldn't have any any more errors and then similarly to the create invoice action here you are you are extracting the data from form data you are validating the types with Zod you are converting the amounts to sense you're passing the variables to your SQL query you're calling revalidate path to clear the client cache and make a new server request and then you are redirecting to redirect the user to the invoices page don't forget to import the update invoice action into your form component I thought I did but let's double check y so right so we should we should be good everything should be working let's let's double check let's do a quick reload here we should uh see Lee Robinson we're going to update this to to 100 and we're going to change it to pending we're going to edit the invoice and oh snap there we go we got we got an error so what is it you know what let me restart the server real quick and go back here run that and let's go back here I'm going to re reload this oh that's going to crash again let's just go to invoices and then go from there all right let's go back to invoices all right so we're back on invoices we've reloaded this let's edit this one make sure that I didn't screw anything up we're going to change this to thousand and we're going to change it to pending we're going to edit ah no what is going on all right are you serious that's that's what it was missing like that's that's what the issue was so yeah so so I just went through a whole bunch of debugging trying to figure out what I did wrong here if if you come across this issue I don't know if I missed a step or what but here in this particular line that it tells you to copy from the tutorial on the update invoice uh invoice schema omit it just has you pass in uh the date of true but I realized that when I was looking at it in vs code and I was looking at the create method or the create invoice uh using that uh invoice schema I noticed that it that one had ID true and I did the same thing here I ended up putting ID true on this one and it resolved the error now I'm not sure if like you know maybe it's breaking something under the hood that I'm not aware of but I'm not getting the error and the crash that I was getting from the database and it did update everything and everything looks like it's working correct and like this this works now and if I update this that might be too too uh too big of a too big of an amount but let me go update Lee Robinson and change him to paid and just change this to like 355 and now I edit and you can see it updated it and it's working so yeah I I just spent a whole bunch of time trying to figure out what was going on there and it seems like adding ID True to this uh fix that which is pretty frustrating so now we're moving on to deleting an invoice here to delete an invoice using the server action wrap the delete button in a form element and pass the ID to the server action using bind so it's pretty much the same thing we did with um the edit so we're going to import. delete invoice which we haven't created yet but we're going to import that into the edit form or I'm sorry it's a buttons component for invoices and then we're going to pass that in here or we're going to import it here sorry wait I'm lost God damn it I'm lost again hold on where am I going so invoices buttons so in the oh it's in the right spot invoices buttons we're going to import that delete um forms there so here we're going to import that and then in the delete invoice what we're going to do there is we are going to change this to we're going to do that and then we're going to change this fragment to a form component there and then we're going to give that an action and that action we're g to pass that I'm guessing I'm going to have to import form because it doesn't like that hold on oh because I'm not it's not a sorry it's not a it's not a fragment it's just an HTML form and then we're going to go back I just got to make sure that I'm doing all of this right so then we're giving that action then we're just going to delete invoice on there and then and that sounds about right there so we'll save that and that's to delete that so so that should work there now inside the actions we're going to create a new action called delete invoice which look that one's got the ID true see I'm thinking that they just screwed up on that and uh and that caused an error which is frustrating when you're doing a course to learn something and then you come across an error like that and can't figure out what the hell is going on um so then I'm going to go ahead and copy that go back into vs code and we're going to go to the actions we're going to add that here wait what what did I not copy last time what's going on why is it telling me that this is so screwed up okay so now I know for sure there's some weirdness going on here so it's got form schema which we were never told to like create a form schema like I I don't even know where it's getting form schema from on update invoice here am I just making a mistake here or is this all screwed up so then like we did the update invoice I fixed that when I was getting that error and now we're doing the delete invoice and in the actions where I'm at now we're going to create a new action called delete invoice right which is this here but what is this form schema this was never done anywhere else and that one's for update invoice so whatever I'm just going to I'm just going to create this function because I think this is just all screwed up somebody somebody messed this up in their uh in in this tutorial I think unless I'm totally missing something I I don't know but here I'm going to create the delete invoice method there call that good um now that should be getting called in there now and since this action is being called and path you don't need to call uh redirect and it will calling revalidate path will trigger a new server so it'll render the table so now this delete button should work here so I'm just going to reload that and now I'm just going to delete that first one there we go it's gone so that worked yeah there's definitely something wrong in the tutorial here that they uh they screwed up in this chapter you learned how to use server actions mutate data you also learn how to use the revalidate path API to revalidate nextjs cache and redirect to redirect your user to a news page uh you can also read more about security with server actions for additional learning you've completed chapter 12 chapter 12 has been the biggest pain in my ass there's definitely some issues with their um code Snippets here after I edit this chapter uh I don't know how long it will be but just to let you know I was recording for a whole hour on this chapter actually uh an hour and 2 minutes so there was a lot of debugging that went on behind the scenes to figure out why it was causing an error when I was editing and if you need to resolve that error it's because they have the wrong uh code snippet here and this particular um update invoice from the invoice schema needs to include uh the ID true just like it did with the um create so on the chap 13 all right now that we are done with chapter 12 here is chapter 13 I'm starting to lose my voice I also got a little bit of a cold and I really just want to get done with this but we're almost there so chapter 13 is handling errors in PR in the previous chapter you learned how to mutate data with server actions let's see how you can handle errors gracefully using JavaScript scripts try catch statements and next js's apis in this chapter we are going to do these following topics how to use the special error. TSX file to catch errors in your route segments and to show a fallback UI to the user and how to use the not found function and not found file to handle 404 errors for resources that don't exist adding TR catch to server actions first let's add javascripts Tri catch statements uh to your server actions to allow you to handle errors gracefully if you know how to do this spend the few minutes updating your server actions or you can copy the code below uh we can do that real quick how many server actions do I have for the sake of the tutorial let's just look at this so I don't have to go in there and try to figure it out myself cuz I'm getting tired and it's kind of late and even though it be quick it's a lot quicker to just copy and paste this so as you can see we're going to wrap the uh SQL query with a try catch returning an error and an error message uh if that error happens and that's as simple as that so this is going to go into all of them particularly this one is going into the create invoices so we're going to just add that real quick to create invoices where or is create invoices so basically just wrapping this with the TR catch there's the TR catch there then we can uh do the same thing here I'm just going to copy this and then just add that there and then we're going to do try and add that there delete that then the error is going to say failed to update invoice and then we're going to do um this last one here and we'll just uh try and then do that move this into that and then if it fails there we do catch error error and then what's the message that we want to return we're just going to copy that and then return the message failed to delete invoice all right so there's all our try catches and now we should handle that gracefully what am I doing all right so let's go back to the tutorial and these are going to be all the solutions for that uh you can see it's all the same thing just wrapping the the uh different um server calls that we are uh wait do we want to return so it seems on the delete they want us to return a message of me of this deleted so let's just add that TOA this to a t so that we have everything exactly how they're asking for it wait hold on hold on hold on wait a minute wait a minute wait a minute okay so there all right so that's where that needs to be all right um all right so let's get back to the tutorial no note how redirect is being called outside of the TR catch this is because the redirect works by throwing an error and would be caught in the catch block uh to avoid this you can call redirect after your try catch and the redirect would only be reachable if you if the try is successful now let's uh check what happens when an error is thrown in your server action all right so in your lib actions we're going to throw a new error uh fail to delete invoice this is going to be the delete right at the top there so that's what it wants us to do and then this is unreachable when you uh try to delete an invoice you see an error on your Local Host okay for so for the sake of trying this let's make sure I save that saving all this let's go here now I'm going to reload this page and now we should just get an error and there's the error and it says failed to delete invoice got it now let's just reload that go back to the tutorial see what the hell it wants us to do next uh and then seeing those errors are helpful when you're developing and you can contach speciic problems uh and also want to show errors to the user avoid interrupt failure and allow your application to continue running this is next this is where next J s error TSX file comes in handling all errors with error uh TSX all right so this file can be used to define the UI boundary in the route segment it serves for catchall for unexpected errors and allows you to display a fallback UI to your users inside your dashboard invoices folder let's create a file called errors TSX and add the following code so so now let's go to our invoices folder here where where am I invoices and then I'm just going to add this file errors. DSX add that and then paste that and then save that and now let's go back I'm guessing now when I run that and we do this there's a few things to notice about the code above it uses use client needs it needs to be a client component and it accepts two props the error is the object of the instance of JavaScript native error object and the reset is a function to reset the error boundary when executed to render the route segment when you try to delete the invoice again you should see the following UI all right let's see if it worked I'm going to reload that real quick and we're going to hit that and no it didn't work you son of a what did I miss what did I miss I got the error there let's you know let's just restart that browser one more time there and see let's go to back to our invoices let's try that again son of a okay so why is that not catching it did I put it in the wrong spot invoices oh ah you see it's always a little little stupid thing like that so I I name that file incorrectly it's error. TSX so now everything should be good since I named it correctly and now let's see if this error reload it real quick just to make sure I know it reloaded but whatever boom there we go we've got an error we've got an error in the console and now we got the uh try again there that reroutes us perfect so that's working awesome great lovely what's next handling 404 errors with the not found function another way you can handle errors gracefully is by using the not found function while error uh TSX is useful for catching all errors not found can be used for when you try to fetch a resource that doesn't exist for example visit this URL here and uh it's a fake and you'll immediately see the error. TSX so we'll go there yeah so here's our error okay and then it's the fake uh uu ID you'll immediately see the file however you want to be more spe specific you want to be more specific and show a 404 error uh tells a resource that hasn't been found you can confirm the resource is not found by answering that so um you can confirm a refor has been found and your fetch resource by ID so this is all right well I want that all right so it wants us to enter add this console log I'm going to skip that I don't need that console log there I'm not going to waste my time with that right now uh now that you know the invoice doesn't exist in your database you use the not found to handle it and then what we do is we import not found into from next navigation and we can use this to invoke the not found okay great okay so basically we go back to that edit page and then what we want to do is then we're going to right after the first promise here if invoice uh if not invoice then we re return the not found method uh and then perfect the page will now throw an error specific to the invoice not being found then to show an error UI to the user create a not found TSX inside the error folder okay so um so so we added that uh if not invoice then not found and we throw that error and now the page will throw an error if a specific invoice isn't found to show the eror UI create a not found TSX file inside the edit folder so now we go back to VSS code we go into this edit folder and here we're going to do not found . TSX and in that we're going to say uh we got to return it but hold on let me just make sure I'm doing the right thing here let's go back to the tutorial so yeah I created that and now we're going to paste this whole pretty little uh not found uh page that they create for us here right into to the new file that we created and save that and then now now now when we go back here and we try to find that same invoice oh it already updated so now we got a you know a little sad face there and the not found and then we can go back awesome all right that that was pretty pretty straightforward there and then if we refresh the route you'll see that it shows us that UI and uh it's something to keep in mind not found will take presidence over error so you can reach out when you want to handle more specifically time to take a quiz which file in nextjs serves a catchall as an unexpected error for your rout segments error TSX yay we just learned that for further reading we can learn more about error handling in nextjs and check out the following documentation cool chapter 13 is done yeah we're almost there all right we're on chapter 14 improving accessibility accessibility in the previous chapter we looked at how to catch errors including 404 errors and display a fallback to the user however we still need to discuss another piece of the puzzle form validation let's see how to implement serers side validation with server actions and how you can show form errors using use form State hook while keeping accessibility in mind all right in this chapter we are going to cover how to use eslint plug-in jsx uh uh I always forget how how you say this it's not Ally it's like uh A1 I I forget there's there's some some cute little way to say that but it's that's accessibility basically uh with nextjs to implement accessibility best practices uh how to implement serers side form validation and how to use react use form State hook to handle form errors and display them to the user so what is accessibility accessibility refers to designing and implementing web applications that everyone can use including those with disabilities it's a vast topic that covers many areas such as keyboard navigation semantic HTML images Colors videos Etc while we won't go in depth into accessibility on this course we'll discuss the accessibility features available in nextjs and some common practices to make your application more accessible if You' like to learn more about accessibility we recommend that you uh the learn accessibility course by webdev so using the eslin accessibility plugin in nextjs by default nextjs includes eslint uh plugin to help catch accessibility issues early for example this plugin warns if you have images without alt tag text also the ARA labels and the RO attributes incorrectly and more let's see how it works and the next line is a script in your Json package so we want to add this uh to our scripts here and go to our vs code go to our package Json and then add that a little Comm here and then add that next lint save that and then I'm guessing it's going to have us run it all right so let's run that real quick I got my terminal all squished up down there here's my other terminal so uh it's uh mpm run lint lint and then we're running the lint there and it says no es lint warnings or errors yeah that's good all right so what's the next step there uh you should see the following warnings well I didn't see this warning uh so I don't know what's going on but uh let's see invoices warning for line column all right so does that not have an all all T let's let's go see so that's invoices on table TSX let's let's look look for that file table CSX in invoices is that what it was uh it was 45 there's no image there so it wasn't that one what what was it it was it was invoices table Yeah line 45 you know what I formatted this so is there image image so I I formatted this and I'm not sure if uh so that has an ALT tag alt tag so all the images on this have an ALT tag but here for the sake of this exercise I am going to remove this and then just uh apparently it wants something in there but all right so then that's that's a blank string now let's rerun that and see if I get an error ah you gotta love it right how about we just don't have the tag at all oh no now it's now it's like no you got a warning so they going to give me a warning in here it won't give me a warning so it doesn't have that so I should get a warning now because I can see the linter is throwing a warning here there we go all right so that's what we should get so I don't know I'm in the right file it didn't throw the error initially but but I I made it throw the error now and what does it want us to do as part of the tutorial uh so you need to add that and then now you should run it okay so I feel like I just did all this but backwards so you saw that just for the sake of the exercise we'll go ahead and put this back I'll just command Z get my stuff back in there save that Rerun this mpm lint and then now you can see there's no errors down here all right beautiful that's working um let's see uh all right improving form accessibility there are three things we're already doing to improve accessibility in our form semantic HTML using semantic elements like input option Etc instead of just div don't use divs everywhere use semantic HTML is what they tell you to do but nobody ever does this allows assistive technology to focus on input elements and provide appropriate contextual information to the user making the form easier to navigate and understand labeling including label for the HTML 4 attributes and uh ensures that each form field has descripted text label this improves the at uh excessive assistive Technologies uh support by providing context and also enhances usability by allowing users to click on the label and focus on the corresponding form input field and then Focus outline the fields that are properly styled to show an outline when they are focused this is critical for accessibility as visual indicators and active element on the screen on the page whatever helping both keyboard and screen reader users to understand where they're uh where they are on the form you can verify this by using Tab and I'm just going to go ahead and tab through this you can see all the stuff being highlighted on the screen I just keep tabing I got the I got this open it might tab into that but you can see as I tab into that and then I tab into that but it seems like the edit buttons getting tabbed into so that's broken um but that's that's the tabbing there and then uh these practices lay a good foundation for making your forms more accessible to many users however they don't address validation and errors form validations go to invoice create and submit an empty form uh what happens so let's go create invoice here in our sweet little application I'm going to open up my Deb Tools in case just in case there's any errors that I need and then uh we get an error we just get an error that's terrible all right you get an error and this is because you're sending an empty form value to the server action and it prevents validating the form on the client for the server so client side validation there are a couple ways that you can validate forms on the client the simplest way would be to rely on for validations provided by the browser by adding the required attribute to the input and select element in the forms for example you just add required and uh let's go ahead and do that real quick where the hell is that create form there's a create form where's where's our inputs here we go there's a required there all right so now we got the required in there let's go back to the form try again hey now now you got to enter a number here people you can't just be all willy-nilly doing whatever you want there all right so we did that uh and we should see that this approach is is generally okay because A ATS support browser validation an alternative to client side validation uh let's see how we can Implement in the next section for now delete uh the required attributes uh if you added them all right well I'll go delete them then just told me to add them now you want me to delete them all right all right so we we we went ahead and uh revert it back to that let's see so server side validation by validating forms on the server you can ensure that your data is in the expected format before sending it to the database this reduces the risk of malicious users bypassing client side validation and have one source of Truth for what is considered valid data this is good to do because you can cause database crash crashes if you send in the wrong stuff and and it's generally good to have serers side validation as well but you could catch a lot of it with just client side validation uh in your create form TSX component import the Ed form State Hook from react Dom since use form state is a hook you will need to turn your form into a client component using the used client directive remember that from earlier so we got to add this so in the create form we got to go and we got to add the um use client and and we got to add this import here so let's go to the create form where we were just is that where we were just at yeah we were just so we already got used client there and then we want to import that use form State there so let's uh let's see what's what's next so then uh invoices create form we did that use form so inside the form component use your uh use form State hook takes two arguments ments uh action and initial State returns two value State dispatch from the form State and dispatch function similar to use reducer pass your create invoice action as an argument of use form State inside your form action attribute and call uh dispatch let's see here so so in the create form TSX we want to do this copy this and then we're going to our action is going to turn into dispatch so let's go here and so here and then we're going to use dispatch here all right and then now we got create invoice and initial state which see create invoice but it doesn't like that it doesn't like that at all let's see let's see what what it's U what it's telling us to do here initial State can be anything you define in this case uh create an object with two key two empty Keys uh message and errors so here's the initial State copy there and go back here okay that's fine and then validate form update your uh invoice schema as follows so so customer ID gosh I'm just going to copy this whole thing there's a lot of little segments to copy so I'm just going to just for the sake of keeping this easy on completing this damn tutorial that I've been working on all day let's uh let's go for this invoice schema here so now we're going to just update that whole thing up there we go okay so now that's some of our validation there all right so we got that I wonder if I'm still I'm still having this create invoice error I don't know why I don't know why and uh kind of sucks because just not sure what the problem is and I'm guessing that this is going to cause a bigger error down the line it's just going to be confusing but hopefully it says something about that so what we just did there is that we uh we got sawed to throw an error if the customer field is empty that's already doing that but it adds a friendly message if user uh doesn't select a customer uh the amount since it's cohering the amount to a type Ty string to number it'll default to zero if the string is empty and it tells Zod uh we always want the amount to be greater than zero with the greater than function that they provide and then the status it already throws an error if the status field is empty but it expects pending or paid so it adds a friendly message if it doesn't have that so that's what that's doing there ah here we go so this is probably going to fix my uh create invoice error that I was getting here because now it looks like um that's going to be taken in state which I don't think it was before so now in the actions we're going to create a type of State see I I just need to be patient so now we're going to go to actions and then in actions we're going to up here we're going to create a type of state and then in the create invoice what was I going to I was going to add State here state and then it's uh type of state is that right I think so hold on did I screw that up let me make sure ah it's previous state okay so I'm taking previous state and that's going to be State that's going to go in there so that's what we want to name it so back into vs code we're going to go here previous state and save that so now I think that other error should go away in the create form I've got too many things ah yeah so now there we go so now my uh my error is gone there which is nice um let's go back to the actions I'm going to close out some of this other stuff that I got open right now just keep the uh the stuff that we're working on because I'm getting lost with all those open uh files there all right so what are we doing so we created that type uh in create invoice uh and we updated create invoice to accept two parameters and the new parameter that it's taking because it had form data already right we were already taking form data is that right I can't remember now yeah we were already taking form data the form data type but now we're going to be taking in a previous state and we wanted that to be a type State and the type state is structured like this which is uh the errors it has an errors object with with the with the customer ID amount status which are all optional and then a message which is also optional as well um the form data is the same as before and the previous state contains a state pass from the use form State hook you won't be using it in the action in this example but it's a required prop then change Zod pars to Zod safe pars all right so let's see here what we're doing is we're going to take that and we're going to put that here in validated fields which I think we're going to swap this bad boy out right here and paste that to validated fields and then now we got all kinds of stuff that's broken all right let's uh let's see I'm sure it's going to have us update the rest of the stuff to get all that the safe pars will return an object containing either success or an error field and will help handle validation more gracefully without having to put logic inside the tri catch block before sending the information to base uh check if the form Fields were validated correctly with this conditional so okay so we're basically going to take this and this is going to replace what we have there now which it's is this in the create or in the update God damnn it I'm lost now this is in create okay so we do that so now it's us in the create so then are we not using this anymore I'm guessing I'm just going to just gonna just going to go ahead and comment that out for the sake of doing this because now I'm a little confused why we're not using that and I'm just going to try to stick to this tutorial we're getting late into it and I'm not really sure some of this stuff is kind of changing a lot and they want us to kind of swap out the stuff that we're doing here so if uh validated field isn't successful we uh return a function earlier in the message with the Zod console log validate uh submit an empty form to see the shape of it finally since we're handling form validation separately outside of the tri catch block you can specify a message to return to the database oh God damn it okay so it wasn't replacing it it was just going before it and all of that is running before we actually try anything so I'm just going to I'm just going to copy this whole thing because I feel like I may have butchered that if you're following along I apologize I thought I was doing the right thing but apparently I wasn't that's why it felt weird if it felt weird you should just know it's probably wrong but now all of that looks right so we have the validate fields which creates a safe safe parse here it gets the customer ID all that stuff if the fields are not successful then we return an error and missing fields and and all of that stuff will run first and then we prepare the data for the database here running the same stuff that we had before all right that makes much more sense now geez what a mess great now let's display the errors in your form content back in the create form component you can access the error using form State uh add a Turner operator that check checks for each specific error for example after the customer's field you can add I hear my kids it's going to get loud in here so we're going to copy that and that's going to go into the customer uh ID field here create form that one goes there and then we're going to add this Turner that they have here we're going to add this um underneath the div to show our errors so let's go where's that user icon Circle saying right here I think that's where that's where it told us to add it I just want to double check that looks right uh under that div all right so that looks like where it wants us to put it so we should see some errors now if I try to submit stuff with nothing in there and try to select this without a customer you see we have this error please select a customer so there's the error that we were looking for there which is nice that's working you can add you can console log the state inside your component to check if everything is wired correctly check the console and Dev tools as your form is now a client component in the code above you are adding the following ARA labels uh ARA described by customer error this establishes a relationship between the select element and the error message container it indicates that the container with ID customer error describes the select element screen readers will read this description when the user interacts with the select box to notify them of Errors the uh customer error ID this ID attribute uniquely identifies the HTML elements that hold the error message for the select input this is necessary for the ARA described by to establish the relationship and then we have the ARA live polite which the screen reader should politely notify the user or the error is updated uh and the content changes when the user uh corrects an error the screen reader will announce these changes but only when the user uh is Idle so not to interrupt them practice adding ARA labels using the example above add the errors that are remaining on the form field so that you should you can now show an error message at the bottom of the form if any fields are missing your UI should look like this so basically what we want to do is we're going to take that same Arya described by customer error we're going to take this and we're going to add here where were we going so choose amount so we got our input for our amount here so here we're going to break that line there and add this and then we're going to say this is customer this is amount error so this is the amount error here we're going to add that amount error there we're going to take that turn area that we got here here where where did I put it I'm just going to copy that um here it is so State errors customer ID if not null we're going to take that and we're going to put it right here and this is going to be amount we're going to change this to amount here then we're going to take this oh wait we got to make sure that the IDS match you see CU I I just did that and then we're going to we're going to make sure that that matches and then we're going to say take this and then we're going to put this on the status so here we have the status and then we have status error and then we're going to write [Music] under going to put the status error here also although this should H I'm I'm kind of I'm actually a little confused on where I should put that error I feel like I should put it on the wrapper but each one is an input because it's a radio so would I where would I put that huh I'm kind of stumped all right well I'm not gonna I'm not going to get too stuck on it the problem is is that this is going to share an ID when I put this here oh damn it that's not the when I put the actual error in there because it's going to reference the same ARA label um which that's going to throw and I think it should throw an error because it shouldn't it shouldn't have the same name but let's see I'm just going to I'm just going to give that a try so let's go to our application and then here here's what it's supposed to look like let's see what it looks like here okay so I have that definitely in the wrong spot um which is okay um that just needs to be moved out so I just need to move that out just have it in the wrong div here so just save that still in the wrong place geez okay so we want it here just format all that and save that okay so now that seems like it's in the right spot which one am I missing please select an invoice status missing Fields failed to create invoice okay I'm missing that last one okay so now let's uh let's run mpm lint and see what what it tells us when we lint this so I'm getting no no warnings I don't know the the linter is not picking up stuff like it's supposed to I don't think so I ran the linter I'm not getting any errors but whatever it there's some extra bonus points here if you'd like to challenge yourself to take the knowledge that you've learned in this chapter and add form validations to the edit form TSX component you can what you'll need is to use the form State just like we did uh and then uh edit the update invoice the way we up we did for the create invoice and uh display the errors on the component just like we did in the HTML and they have the solution here when you're ready to do it and and that's that's everything you need but that's extra credit and bonus stuff that I don't think I'm going to do cuz I'm trying to get to the end of this tutorial and course and I getting really close and really tired and that wraps it up for chapter 14 up next is chapter 15 all right we are on chapter 15 adding authentication in the previous chapter you finish building the invoices routes by adding form validation and improving accessibility in this chapter we'll be adding authentication to our application so what we'll cover is what is authentication how to add authentication to our uh app using NEX O.J how to use middleware to redirect users and protect your routes and how to use reacts use form status and use form state to handle pending States and form errors so what is authentication authentication is a key part of many web applications today it's how systems check if a user is who they say they are a secure website often uses multiple ways to check a user's identity for enhanced security for instance after entering your username and password a site may send a verification code to your device or use an external app like Google Authenticator uh this is two- Factor authentication f 2fa it helps increased Security even if someone learns your password they can't access your account without your unique token authentication versus authorization in web development authentication and authorization serve different roles authentication is about making sure the user is who they say they are you're providing your identity with something you have like a username and password and authorization is the next step once a user's identity is confirmed authorization design decides what part of the application they are allowed to use so authentication checks who you are and authorization determines what you can do or access in the application so it's time for a quiz which part best describes the difference between authentication and authorization so authentication determines what you can access authorization verifies your identity authentication and authorization are both uh both decide what parts of the application a user can access authentication verifies your identity authorization determines what you can access there is no no difference both terms mean the same thing that's not true we just read it on the very last line this is just too easy all right so now we're going to create a login route by creating a new login route in your application called uh SL login the and paste this uh following code okay so this is going to be we're going to do uh right in the app directory we're going to do login and we're going to create a page so here we go let's go back to VSS code let's close all this I'm going to close all these start with a fresh fresh little little setup here so a new folder here we're going to create login and then in that folder we're going to create page this is starting to feel a little familiar now I'm starting to get the hang of how nextjs is set up that's that's nice so in this login page we're going to copy and uh we're going to paste what we just copied that looks good that's our login page back to the tutorial so you'll notice that the page Imports login form uh you'll be using with your component later in this chapter uh okay so that's up here and then uh NEX OJs we will be using NEX OJs to add authentication to your application next OJs abstracts away much of the complexity involved in managing sessions sign in and sign out and other aspects of authentication while you can manually Implement these features the process can be time consuming an error prone NEX o simplifies the process providing a unified solution uh for o and in nextjs applications setting up next o so let's set up next OJs in your project run the following command in your terminal so let's copy that go back to VSS code this is our open Terminal we'll paste that mpm install next off at beta bcrypt and now now that's that's installed now what's the next step here here you're installing the beta version of O uh NEX o which is compatible with NEX js14 you're also installing bcrypt which is a library that will help you hash passwords next uh generate a secret key for your application this key is used to encrypt cookies ensuring the security of your user sessions you can do this by running the following command in your terminal all right so we're going to take this and we're going to run that command in our terminal like that and now we got a code here that I'll have to hide or delete or change so that nobody steals it and I end up you know getting hacked or something stupid like that then in your EnV file you'll notice two variables off secret and off URL now in your off secret you add that code that you just generated and in your a URL you will put this path in there all right so let's go into our EnV down to our off the secret there and then and then we already have our off path there so we'll save all that and then we'll go back to the tutorial uh for o to work in production you'll need to update your environment variables in your versel project 2 check this guide here on how to add environment variables on Bell adding the pages option uh create an O config TS file at the root of your project that exports o config object this object will contain the configuration objects for next OJs for now it will only contain the pages option here so we're going to copy that we're going to create that off config.sys make sure we don't already have it fig. TS there and then we're going to paste that in there and that looks good there let's go back to the course to see what it has to say there you can use the pages option to specify the route for custom signin sign out and error Pages it is not required but if you don't provide it o uh next o will use its default signin sign out and error Pages by adding signin login uh into our Pages option the user will be redirected to our custom login page rather than the O uh next o default page protecting your routes with nextjs middleware next add logic to protect your routes this will prevent users from accessing the dashboard Pages unless they are logged in so here under the pages uh so we'll add call backs and then authorize request is logged in check the double bang off [Music] user say okay say so let's copy this not really sure what it's doing but for the sake of the tutorial I will copy that into here and then so now I'm getting some errors that's not good also looks like that's not closed off so now that's closed off still not sure I need to pass those it's a typescript error that it's given me here let's see I think I screwed something up there no okay so that looks good I don't know uh the type errors that it's giv me hopefully that'll fix it the authorized call back is used to verify the request that is authorized to access the page via nextjs middleware it's called before the request is completed and it receives an object with the and request properties the off property contains the user session and the request property contains the incoming request next you will need to import the auto the off config object into the middleware file and the root of your project to create a file called middleware dots and paste the following code so I'm going to create middleware Notts and I'm going to paste this in there so in our root here file TS create that there and then paste that there save that still guessing because we don't have the types here I think that's that's what it's complaining about um hopefully it doesn't break anything I don't feel like dealing with that right now I just want to get through this tutorial because it's it's been a long day it's been a long day uh all right so here we're initializing o uh next o with the O config object and exporting the O property you're also using the matcher option from middleware to specify that it should run on specific path the advantage of employee middleware at for this task is that the protected routes will not even start rendering until the middleware verifies authentication enhancing both security and performance of your application password hashing to store passwords securely you need to Hash them this process converts the password into a fixed length string of characters which appears random providing a layer of Security even if the hash is exposed in your CJs file we've used in uh B encrypt to Hash the password before storing it in the database you can use the B encrypt to compare that uh the password entered by the user matches the one in the database however bcrypt relies on no JS AP is not available in nextjs middleware to solve this you will need to create a separate file that Imports bcrypt and uh the new file will not be imported into your middleware file create a new file off TSN that spreads your off config option all right so offs in our root and then we're going to spread out our off there all kinds of all kinds of uh typescript errors I'm I'm starting to see here so hopefully hopefully it'll it'll just not give me a hard time I'm I'm tired I don't want to I don't I don't want to deal with that right now adding credentials provider next you will need to add the providers option for next OJs providers is an array where you list different login options such as Google or GitHub for this course we'll focus on using the credentials Prov provider only the credentials provider allows users to log in with a username and password okay so we'll add that real quick right here and then we got to take this credentials provider that we're copying from next o here and add that here ah there we go and that fixed the error that I had there awesome that's great I love it when the errors fix themselves all right so good to know although we're using the credentials provider it is generally recommended to use alternative providers such as ooth or email providers see next o uh docs for a full list of options adding a signin functionality you can use the authorized function to handle the authentication logic similarly to server actions you can use Zod to validate the email and password before checking if the user exist in the database so here in that same off uh TS we're going to uh import Zod and then add that to the credentials to to do a little bit of validation to make sure that they enter some valid stuffs so I'm just going to copy this and replace our credentials uh with that oh crap there's that format that so it looks a little bit cleaner and got an error there but hopefully it'll resolve itself here in a second after validating the credentials create a new git user function that queries the user from the database so now we're going to import bcrypt and we're going to import this definition uh user from our lib so let's go do that sa that and then let's go see what else we got to do here so then we're going to take we're going to take all right so I'm probably going to end up copying all this so that I don't have to figure out where to put everything because it looks like we're updating some of our parameters and we're we're putting in a try catch and I'm just I kind of want to look at the code real quick to to see what what I'm doing here so then we add this uh async function get user that takes in an email returns of Promise undefined so uh so then we have the try which is it it selects the user from where email matches email and then it Returns the user rows if not it throws an error and then so that's happening first and then we check if parse credential success then we do that in the credentials for the provider okay I'm just going to copy this whole thing because honestly there's a lot going on there and I don't feel like dealing with placing that in all the right spots so I'm going to just highlight all that and save it nice and easy let's see then we call bcrypt compare to check if the password's match so here in that last part of [Music] the success so a wait bcrypt compare so we do that if the password match return user if not invalid credentials and then let's go ahead and place that where it needs to go so it looks like I need to put it right there so if not user return null and then we add that and then return null so just trying to see where I need to put it not user null so then we add that return null I think right here it's good that looks right format all that getting an error but we have user password that's possibly undefined all right so let's let's go back to our tutorial so finally if the user passwords match we want to return the user otherwise return null to prevent the user from logging in updating the login form now you need to connect the O logic in your login form in your actions TS file to create a new action called authenticate this action should import the signin function from Au TS so in actions we're going to paste this asynchronous function like so so let's go back to that that old actions um file that we got going on here and got a lot of stuff in that actions uh and then we're going to paste that actions there and in that sign in I need to import that um from where was that coming from sign in comes from oth copy that we'll go back back here all right so that looks good save that I don't think I have any errors down there so that I still got that that so this I can delete this to fix that oh now all kinds of all kinds of errors are happening we love when that happens on a tutorial where you're not really sure what the hell is going on all right well oh you know what the error might have been coming from the page that I'm on CU I don't think I'm supposed to be on that page uh so let me let me go here now a crap all right so what's what's the error that we have here so it says property of undefined read map middleware TS off config let's see what's going on in middleware so I'm getting an error but I'm going to finish adding the rest of this stuff because I it might be connect connected and I don't I don't want to jump the gun and try to debug something that might just be resolved by doing the next step in this uh course so let's see um if there's a credential sign in error you want to return it so that you can show the appropriate error message so that's probably my error see I'm I I get ahead of myself too much finally in your login form uh TSX component uh react use state so in our login form here we got to add the used client you know this is the full the full form I'm going to copy and paste this they're importing a bunch of stuff they're importing the actions authenticate they're adding some used form state they're adding an action to the form and then we've got some uh credential signin uh block a code here that will show if this is true and then we got a login button here so I'm going to copy this whole part and I'm going to go back to my login form page here where where the hell is it it I think it's this one yep so that's our login page I'm going to make that error smaller highlight all that and then replace all of that with that now this is throwing an error I love when I get all these these new errors like how is it that I am using the latest version of NEX JS for this latest tutorial and I'm getting errors in the tutorial like it's so annoying to get errors in a tutorial and it's even more annoying to get errors in a tutorial when it's official documentation and an official tutorial from the people that create this project it's not like some dude on YouTube who messed up it's like man you guys messed up and uh screwed this all up and you guys are like the people that created this so it's annoying looks like I'm I'm in a loop here on this era down there so we're just going to we're just going to keep doing the tutorial and hopefully this just resolves itself I'm like super tired it's it's like late I've been I've done so many of these it's almost 5:00 and I'm I'm kind of I'm kind of over it if I'm being honest all right so I copied all that I put that in there and now we're going to add the logout functionality logout functionality is going to go on the side nav and in the log out uh side nav we're going to so in the log out uh we're going to do sign out from o we're going to go into the side now side nav and then we're going to import this sign out there and then we're going to add this form element right under the nav links think it wants it right there not sure why why is it why is it giving me a hard time there did I add it in the wrong spot hold on so under nav links above the button there's already a form there so I'm not I'm not sure I'm not sure why there's already a form there and this is within a form this is like a form there's already a form here there's a form there and they they obviously have like some ellipses here to say that there was code there it's kind of annoying that they don't just show the whole block um but whatever we'll figure it out so under naav links under the div under naav links is where I'm going to add this so it goes there and I mean it needs to close the form that's that's what it wants me to do so I'm going to add that I'm still getting an error which is pretty frustrating now it's saying to try it out now uh you should be able to log in with this credentials uh I don't think my app's even working uh so this is hosed uh so I went to the gym I came home took a shower ate some food and started trying to figure out what I did wrong here and I just copied the wrong stuff I wasn't paying attention there was nothing wrong with the chapter 14 everything was correct I just screwed up and didn't copy the oom fig uh correctly and I missed a providers so I had to kind of go down a rabbit hole to figure out what it was that I was missing excuse me and then finally figure that out so everything worked and I'm pretty sure that I was towards the end of this but I will say that if you follow along with this chapter and copy everything correctly you shouldn't have an issue like I did um but right now I am going to actually try this out with this uh username and password and see if it lets me in so we're going to log in Moment of Truth here a so on the login page we have what's this module not found so let's uh let's go look for that now just when I thought I was done dealing with this just glad it's a different error so that's progress so let's go let's go look for that button where is that module not found can't resolve uh button and that's in login page. TSX we'll go [Music] there well where is that button that's supposed to be here seems like my button is part of the UI so where's this login page login up page so it's looks like that path is screwed up so let's just let's see if we can fix that and then was in UI I think it's it's probably the same button right okay let's see if that fixes that so that was copied right from the tutorial so that might actually be something that was wrong there but let's go back and make sure that that fixed it that I import the right button this time oh yeah there you go so um that's a really long button but it seems like it's working now um there's a username and the password was 1 two 3 4 5 six don't save that let's see if it logs me in hey look at that all right it worked no issues there H I'm really glad to be done with that chapter that um that chapter was was quite the doozy but there you can see that I logged in I'm authenticated this is behind the authentication so it worked and then if I sign out that should kick me back to the login page which it didn't that's weird I shouldn't be able to get to the dashboard without being signed in maybe this sign out button is not hooked up which it should be from the tutorial so let me make sure that I hook that up so here we have sign out from o and then we have use use server or server action inside that form that's underneath the class or the nav links let's make sure we have that on the side naav component side component I have that here that was the button that I clicked [Music] right so wait a minute hold on hold on hold on that's why I have that incorrectly wrapped so this form I I think I did some copy pasta there I shouldn't have done let me double check that what's this look like yeah so that's I I screwed that up all right so let me make sure I put the form on the right spot here so let me just delete that and then delete this opening tag there and now replace that form there and now that should work let's load that go back and then sign out and that should now it should kick me back there we go awesome awesome so if I go here I should go into this page and then this should work here and oh damn it now I forgot the password they gave me what was it the username there's the username let's try it one more time just to make sure everything works and then it was one two 3 4 5 six log in don't save sweet it works awesome all right that wraps up that chapter I am so happy to be done with that chapter all right so we just finished chapter 15 we are on to chapter 16 the final chapter of the tutorial of the course for nextjs 14 I'm really excited to be here that last chapter had me stuck because I made a mistake of copying and pasting the wrong stuff and not paying attention to what I was doing it's too busy trying to make the video and follow along and all that so just pay attention and you'll be fine don't be like me all right so the last chapter chapter 16 is adding metadata so metadata is crucial for SEO and sharability in this chapter we'll discuss how you can add metadata to your next JS application so in this chapter we are going to cover topics like what is metadata uh types of metadata how to add an open graph image using metadata and how to add a fabcon using metadata so what is metadata in web development metadata provides additional details about a web page metadata is not visible to the users visiting the page instead it works behind the scenes embedded within a Page's HTML usually within the head element this hidden information is crucial for search engines and other systems that need to understand your web Page's content better why is metadata important metadata plays a significant role in enhancing a web Page's making it more accessible and understandable for search engines and social media platforms proper metadata helps search engines efficiently index web pages improving their ranking and search results additionally metadata like open graph improves the appearance of shared links on social media making the content more appealing and informative for users so what are some types of metadata there are various types of metadata each serving a unique purpose some common types include title metadata responsible for the title of a web page that is displayed on the browser tab it's crucial for SEO as it helps search engines understand what the web page is about so here's your title tag that usually goes in your head uh description metadata this metadata provides a brief overview of the webpage content and is often displayed in search engine results so here's a meta tag with the name description and the content is a brief description of the page content keyword metadata this metadata includes keywords related to the webpage content helping search engines index the page so metadata or meta tag with the name keywords and here's some keywords in the content and then we have some open graph metadata this metadata enhances the way a web page is represented when shared on social media platforms providing information such as the title description and preview image so here is meta property OG title content Title Here meta property OG description then you have your uh content and the description there and then finally you have the meta property OG which is the open graph and image content image URL here okay and then you have your Fab icon metadata this metadata links to Fab icon a small icon on the web page and that is displayed in the browser address bar or tab which is the you know little nextjs icon that you see here that's your Fab icon and your GitHub and your chat GPT Fab icon there so and that's put in with the link tag and then you uh with the real attribute icon and the href to the path to that all right adding metadata nextjs has a metadata API that can be used to define your application metadata there are two ways that you can add metadata to your application config based which is uh export a static metadata object or a dynamic generate metadata function in the layout JS or page JS file and then you have a file based uh approach which nextjs has a range of special files that are special spe specifically specifically recognized for metadata purposes you have your Fab icon. I your Apple icon jpeg your uh an icon jpeg utilized for Fab icons your open graph image and your Twitter image uh employed for social media images your robot text which provides instructions for search engine crawling and your sitemap XML which offers information about your website structure you have the flexibility to use these files or static metadata and you can generate them programmatically within your project with both of these options nextjs will automatically generate the relevant head element for your page is your pages uh Fab icon and open graph image let's see in your public folder you'll notice that you have two images a Fab icon Ico and an open graph uh image JPEG move these images to the root folder of your app uh doing the after doing that nextjs will automatically identify these files in your Fab icon and OG image and you can verify by checking the head element in your application Deb tools a good to know is that you can also create dynamic images such as the respon uh using the responsive image Constructor all right so we're going to go to our public folder and we're going to move those two images into our app folder so let's do that real quick let me close all these let me close all these too I'm I'm done with all this stuff and you can see that I was in the in the weeds there with all these all these files that were open all right uh so where is my public there's my public and then we have our Fab icon and then our open gra image here and they want us to move that into our app folder so we'll just move that right there move that all right so now in our app folder we have those two images there perfect perfect perfect all right so now let's go back and see what the next step is all right for page title and description oh first did it say now we can check to see let's go check let's let's check all right so now let's check we should be able to see that in our head tag let's just uh open up our head here and see if we can find it there's the OG image and then there's OG image image it's in here somewhere so there's that open graph image PNG which is saying that the path is in the rout uh there and here's the Fab icon okay I'm seeing them but I'm not I'm not totally sure if this is working but that's that's there um so then now we're going to go to the page and title descriptions you can also include metadata object for any layout JS or page JS file to add additional Page information like title description any metadata in layout JS will be inherited by all pages that it uses your root layout uh in your root layout create a new metadata object with the following Fields so so in our root uh so our app Root layout we have uh an import metadata here and then we have a metadata object type metadata with a title description and metad database which is a URL here so we're just going to copy this chunk right here and we're going to go and open the layout in app so that's this and then right here at the top we are just going to paste that metadata right there right there all right and then let's go back to the tutorial so nextjs will automatically add the title and metadata to your application you can see now if you look up here it changed to Acme dashboard before it was just Local Host um which that's cool that that's working so that's that's nice that's nice um let's go back here and then uh let's see but what if you want to add custom title for a specific page you can do this by adding metadata object to the page itself metadata is Nest is nested pages will override the metadata parent so for example example if you go to the invoices you can add this all right so let's go to the invoices page and add that and see what it changes the title for when we're in invoices so where am I here app dashboard uh invoices and then invoices page here at the top here we'll just go ahead and add our metadata save that so it should say invoices Acme dashboard now we'll go back to our application here I got to authenticate and I forgot the uh I forgot the uh username that they gave me so I'm going to have to go back to this chapter and so it's user atmail decom I'll just remember that for the last time for the next time so user at next mail and it's 1 2 3 4 5 6 log in don't save that now our invoices should say invoices Acme dashboard perfect so now I logged in and as you can see we got our invoices Acme dashboard up here uh which shows that the ma that the meta data is working there so let's go back to chapter 16 and go back to where we were at here and now uh let's see now this is okay but it's not very dry dry is don't repeat yourself all right uh which is something that you should do to keep your code clean uh you're repeating the title of the application in every page and it's if something it changed like the company name you'd have to update every page instead you can use title templates find in the uh uh in a you can use title templates in the metadata field uh object to define a template for your page titles this template can include the page title and any other information you want it to include so in your root layout update the metadata object to include a template so here is that title template so let's copy this go to our root layout our root layout and let's swap this out don't need to import that twice all right so now we have that that's using this temp template all right so that looks good now what's the next step this is uh the percent s is the template that will be replaced in the specific page now in your dashboard invoices page you can add the page title cool so then now we just add this to the invoice page instead of having that other stuff repeat itself and then there you go awesome now we should still have that still working how it was yep there you go it's still working how it was there and then uh let's see so now practice adding metadata now that you've learned about metadata practice adding the titles to your other pages and your login page your dashboard page your customer page and your dash board invoice create page and all that stuff I'll be honest uh for the sake of this tutorial and considering that I've I'm kind of like done and tired of doing this I'm not going to go in and add the metadata object that feels very simple and mundane and kind of uh something I don't feel like doing for the sake of learning because I feel like I already learned how to do that once and I don't need to practice that cuz that wasn't anything that was very complex so I think I'm just going to wrap this up the next Js metadata API is powerful and flexible give your gives you control over your applications metadata here we've shown you how to add some basic metadata but you can add multiple Fields including keywords robots con con canonical I always have a hard time with that word and more feel free to explore the documentation to add additional metadata oh look at that we are finishing the course baby all right so that was chapter 16 we are done the next steps you know it's congratulating me cuz I did such a good job you've completed the nextjs dashboard course where you learned about the main features of nextjs and best practices for building web applications but this is just a beginning nextjs has many other features it's designed to help you build small side projects uh your next startup idea or even large scale applications with your team here are some resources to continue exploring nextjs so we got some documentation templates the nextjs repo and versel YouTube and then now it says to share your next JF app we encourage you to share the tool you built on X if you do please mention our team nextjs so that you can take a look we'd love to get your feedback on the course as well if you enjoyed this course continue learning by building yay we completed the course I'm so happy all right we're done all right tell me what you thought of this video I I feel like this is kind of like the gaming channels that do the let's play this is kind of like the let's learn and uh I kind of enjoyed this I I definitely want to mess around with more nextjs it's it's cool doing the course and recording it and sharing it and you know getting stuck and having some troubles with it and working through that and if you enjoyed this you want to see more videos like this give me some ideas of some courses you want me to do and some tutorials you want me to walk through because I I genuinely had fun I've been wanting to learn nextjs for a while and now I feel like I know enough to go out and start building some stuff with it and if I get stuck in any of these particular areas I'll come back and reference the course and documentation and yeah that's it all right with all that thanks for watching and I'll see you next time
Info
Channel: Dorian Develops
Views: 43,682
Rating: undefined out of 5
Keywords:
Id: eZJJ189JTks
Channel Id: undefined
Length: 317min 46sec (19066 seconds)
Published: Sun Nov 05 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.