Build and Deploy a Full Stack Next.js 13 Application | React, Next JS 13, TypeScript, Tailwind CSS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
embraced by many companies including the Washington post tick tock twitch and even popular figures like Mr Beast next.js shows no signs of slowing down with more and more stable features every now and then nextgs continues to grow top companies steady adoption of nexgs affirms its position as the future of web development there is no better time than now to become proficient in nextgs in this course is specifically designed to help you achieve that goal before anyone else throughout the course we will build and deploy a full stack triple clone using the most up-to-date and advanced nexgs features powered by graph base with a modern design that closely resembles the real world triple website providing a familiar and Visually appealing interface browse different kinds of projects people share filter them by a category and handle the data display via smooth pagination fully functional authentication and authorization system using both JWT and Google art provider share your best projects with the community through a dedicated create post Page look at the details of a project with a related Project's functionality to explore more projects edit the previously created projects including the ability to re-upload images from your device to the cloud delete projects with a simple one-click process a portfolio-like profile page where you can see your projects as well as the project profiles of other users and all that is 100 mobile responsive and let me tell you I haven't been this excited about a project in a long time this course is perfect for fully understanding how modern next 13 apps truly work behind the scenes all this by leveraging nextgs's complete server-side rendering features with the most recent best practices after you develop this app I'll even teach you how to deploy to the Internet so you can share it with your friends potential employers and put it on your portfolio now you might be wondering what are the prerequisites for building such a great application well you need to know the basics of modern web development using react if you haven't already first watch our latest nextgs crash course by clicking the card on your screen or forward the link in the description and then come back to build this comprehensive next gs13 application by watching this video last time we revealed we were working on the ultimate next 13 eBook that covers everything you need to know to become a professional next.js developer the ebook covers the complete nexgs roadmap essential nextgs Concepts new next 13 features extensive guidance on building scalable next to a certain projects from scratch and project ideas you can build and deploy to put on your portfolio and get a job this ebook is the most comprehensive resource we'll ever create so we're still finalizing it to make it perfect thankfully as the last time the first 1000 people that click the link in the description will get it for free so sign up right now via the link in the description to find out if you're in the first 1000 don't miss out you're gonna get the first few chapters really soon and then once it is fully done the complete ebook in this course you'll gain knowledge on various topics including establishing application routes utilizing server-side rendering implementing filtering functionality complete pagination capabilities handling image uploads understanding and writing proper typescript without using a single any type and all of this is made possible by graph base graph base is a serverless graphql platform that enables you to ship high performance applications faster than ever it includes a serverless graphql API which is the easiest way to build and deploy apis by creating schemas in this course I'm going to show you how to create two different schemas one for our project and one for our user how to create relations between them and how to perform crowd operations on them another one of graph based features are connectors that Stitch graphql or open API apis into a unified data layer they also offer Edge resolvers and Edge caching to customize your graphql API with Edge functions then you can also utilize their serverless database in full text search built in there's also a CLI for local development with zero configuration and a git-based workflow that allows you to preview environments for every git branch and finally there's auth so you can integrate your provider using openid connect or jwts these are only some of the features that will enable you to build complex applications incredibly easily and today you'll get first hand experience on how to implement them on a real application if this video reaches 20 000 likes I'm recording more next day is 13 videos with that said let's dive right into the course foreign [Music] as we always do to get started we're going to create a new empty folder on our desktop and in this case let's call it next js13 underscore flexible or feel free to call it however you want to and then drag and drop it into your Mt Visual Studio code once you're in go to view and then terminal to open the integrated Visual Studio code terminal there we first want to set up a new nexjs13 project by running MPX create Dash next Dash app add latest and then run dot slash to created in the current Repository this is going to ask you if you want to install the following package so press Y and then enter and now we have this little questionnaire asking us what environment we want to create for producing our application so first it's asking us whether we want to use typescript and we're going to say yes then do we want to use eslint in this case we're going to say no would we like to use Tailwind well of course do we need an SRC directory not in this case and we absolutely need the app router and we don't need to customize our default import Alias and this is it it's installing the default dependencies and spinning up our next js13 application on top of the default packages we're gonna also install a couple of other ones that are going to help us develop our application so we can say npm install and then start noting them one by one the first one on the list is going to be add headless UI Dash forward slash react we're going to use it to create a combo box and drop down elements then we're going to use cloudinery for the image upload then we're going to use Json web token and add types forward slash Json web token we're going to use this for authentication of course then we're going to use a package called graphql Dash request to make graphql actions and for auth we're going to also use next auth with that said press enter and wait a couple of moments until all of our dependencies are installed let's not forget one Dev dependency so let's say npm install add graph base forward slash SDK dash dash save Dash Dev this phenomenal SDK is going to significantly speed up our workflow with graph base great now we have everything we need so let's check out which files and folders nextgs created for us we have our icon globals.css layout.tsx and the page we also have the public folder and the node modules I like to start from bare Beginnings to give you a full explanation of the entire file and folder structure so what we can do is completely delete the app folder and the same thing goes for the public folder now we can recreate the app folder and within it we need one most important file which is the page.tsx this is going to be the starting point of our application so inside of here we can say const home is equal to it's going to be a functional component that's for now simply going to return a div that contains an H1 that's going to say home and of course we need to do export default home at the bottom this should be enough now to see if this really is enough to spin up our application let's go ahead and run npm run Dev to start our development server it is live on localhost 3000 so control click it and we indeed do see the home page which is great believe it or not when you're finished with this video this home page is going to turn into this a complete dribble.com clone but with a Twist it's gonna be for developers so every single developer will be able to upload and share the projects they've developed so with that said I hope you're excited let's put our browser side by side with our editor great and now we can proceed with creating the file and folder structure that we'll be using throughout the rest of the video inside of our app folder we're gonna of course have all of our pages but we're gonna also have apis so inside of here you can create an API folder inside of which later on we're going to put our API routes next in the app folder we also need a globals.css file this file is just going to contain some common Tailwind classes so down in the description in the GitHub gist which we'll be using couple of times throughout this video you can copy and paste these utility classes that are going to help us develop this project keep in mind this is not the entire code these are just some classes that are going to make the development of our project simpler and they're going to allow us to focus on what matters which is learning the latest and greatest of what next gs13 is after the globals we're gonna also need a public folder so below that GitHub gist you'll be able to find a zipped public folder so simply download it unzip it and then paste it right here next to the app folder within this public folder we're just going to have some icons that is it and one of these icons is going to be the favicon so simply move it within the app directory we need it here so it is immediately reflected on our home page next we're gonna have a components folder inside of here we're gonna of course put all of the components that we're going to use within our next JS Pages then we added the globals.css but we also need to update our tailwind.config.js so again in that GitHub just down below you can copy it and paste it here we add some useful utility classes for colors box shadows and screen sizes now we're done when it comes to Styles but we are also using typescript so we can create a new file called common dot types dot TS and in that same GitHub gist you can find the interfaces and types we'll be using throughout the project don't worry since we have them typed out right here because once we create each one of these objects in the code we're going to revisit this file and explain how this typescript work for each one of these and how to create these subscript interfaces great enough of the setup let's begin with our home page our home page is going to be a section element that's going to have a class name equal to flex Dash start Flex Dash call paddings and mb16 for margin bottom and then inside of there we'll want to render some categories so for now let's simply type categories as you can see these are going to be the categories and then below that we're going to have the posts so right here we can say posts finally below the post we're going to have some pagination if we have enough elements so for now here we can say load more and these are going to be three integral part of our home page for now let's simply turn them into H1 tags and then later on we'll be able to turn them into special components that we're going to reuse across the page so for now just turning them into H1s and they're gonna fall one below another now the reason why I did this is just to show you that this is it this is the entire homepage categories posts and more everything is going to be happening within this small window right here we'll be doing some heavy server side rendering we'll be changing the categories and all that good stuff but for now let's focus on the layout let's focus on what's outside of this section that's going to be the nav bar and the footer footer is going to contain a lot of links and of course the nav bar is going to contain the authentication so the way nextges handle that is with a special layout dot TSX file inside of here we can immediately modify the metadata of our website so let's call it flexible and here you can give it a description so I'm going to say something like showcase and discover remarkable developer projects now I hope I won't confuse the developed side in this one well I definitely won't at this point because they're looking completely different but as we continue developing it it's going to be much harder to differentiate it too great so this is it when it comes to our layout as you can see here we have a root layout with the children inside of it and the children essentially represents this page that we have right here so of course above the page we want to have the nav bar that's going to be still within the body but above the children we're gonna have the nav bar which for now we can type like this and below it we're gonna have the footer and just to follow some good practices we can wrap our children in a main section kind of like a main part of the home page there we go and we can indent it properly now you can immediately see how our layout is coming into place inside of this file we're going to also import our globals.css because we have to import them somewhere to be able to use them so that's going to be import dot slash globals.css and for now this is just going to change the font we can also start with creating the nav bar and the footer components So within the components folder let's create a new file called navbar.jsx oops it's not going to be jsx it's going to be TSX because we're working with typescript and we can also create a footer.tsx for now we can run a special shortcut called rafce inside of each one of these this is going to create a quick react Arrow function component with a default export if this didn't work for you go to extensions and search for es7 plus react react native Redux Snippets install it and then it should work so now within our layout we can simply import the navbar component it's going to be a self-closing one and we can also import the footer component that's going to be like this now a cool trick is you can double click it and press Ctrl space or command space to immediately import it by clicking on this link and I'm going to repeat the process with this one so now you can see that we have globals and we have the imports from these two components if that Auto Import didn't work for you no worries you can just manually import it by typing import navbar from add forward slash components forward slash navbar you can notice these paths that nextgs is automatically creating so you don't have to do da. and then get to the path you can do it immediately now I'll be making use of this shortcut of controller command space and then automatic import throughout this video so if it doesn't work for you no worries just import it manually from the components folder great with that said we now have our components and let's start of course with the nav bar so moving into the nav bar this is going to be the first actual component we'll be creating to start developing our navbar we can turn this div into an HTML5 semantic nav tag and then within it we can have a div to provide some structure the nav is going to have a class name equal to flex between written like this and a navbar class and the snapbar class is one of the predefined classes we created that you'll be able to find within the globals this is going to do nothing more than just apply some paddings borders and colors that is it the div below is going to have the class name equal to flex one Flex start as well as gap-10 and then inside of there we want to have a link tag this link is going to come from next forward slash link so we can immediately import it at the top and since we're next we don't need to import react this link needs to have an href and this one is going to point to just forward slash because it's going to be the home page now we can create a logo and that's going to be a self-closing next gs13 image which again we can import from next image we can give it a source equal to forward slash logo dot SVG we can give it a width I found the value of 115 pixels to work the best with a height of about 43 pixels and the alt tag can be flexible if you save this you should be able to see a nice logo appear on the top and if you click it it should redirect you to home below this image and below the link we can create a UL an unordered list that's going to have a class name equal to on extra large devices we wanted to show and usually we want to hide it so it's going to be hidden the text is going to be small and the Gap is going to be 7. by the way if you haven't noticed already we're using Tailwind for all of the classes here so if you're new to Tailwind no worries if you don't know what one of the classes I write does simply go to tailwindcss.com and then just search it it is as easy as that so if I type Gap you'll immediately be able to see what the Gap does sets the gap between elements now one cool thing is that if you hover over this class name it's going to tell you exactly what CSS property is being applied and for this to work you need to have the Tailwind extension installed so simply install it and then as I write classes you'll be able to just hover over it and see exactly what this applies for example Excel Flex applies this entire block of CSS within this UL we want to map over some of the links and we won't write them by hand of course you want to store all of these links in a folder called constants so right here in the root of our directory we can create a new folder called constants and within it we can create a new index.ts file in the GitHub just down below you'll be able to find this file which you can simply copy and paste right here this is nothing more than just some links for the categories and for the nav bar that is it so I wanted to save you some time from writing all of this by hand and just hand it over to you immediately so we can focus on what matters So within this UL we can open a new Dynamic block of code and we can say nav links and we can immediately import that from add forward slash constants right here we want to map over them so we can see nav links.map where we get each individual link and for each one we want to have an immediate return meaning just parentheses instead of curly braces and for each nav link we want to return a link that link is going to have an href equal to link Dot href and a key equal to link dot key right here and within it we can say link dot text so if we now save this you should be able to see some new links appear right in our nav bar right now we cannot see it it's possible because we're not on the extra large device so if we zoom out a bit or if we zoom in and unfortunately we cannot see it because I got an internal server error so if I look into my terminal it seems like it broke I'm not sure why it does happen from time to time but if we stop our terminal and run it again by running npm run Dev we should be back on track really soon as I told you in the intro of this video next.js is great but it's full of quirks and features some features are great like server side rendering but it has some quirks like constantly breaking not having enough documentation and well you're gonna see it throughout this video but I'm gonna teach you how to overcome all of the obstacles to be able to get only the benefits so right now we're back and thankfully we can see our logo but we cannot yet see our nav links so if I go to nav links they're properly imported and maybe if I zoom out a bit we'll be able to see it yep because I put only half the screen for my browser so if I go back to 100 and I show it you'll be able to see all the links but we don't necessarily need to show them on mobile devices great with that said we can now go below this ul and below this div and we can create one new div this div is going to have a class name equal to flex Center and a gap between the elements of four there we can either display our user profile photo or a button to sign in so later on we'll get access to something known as a session so we can say con session is going to be some kind of an object so for now we can open a dynamic block of code and say if session exists that means that our user is logged in which means that we can show a react fragment inside of which we're going to have the photo the user photo as well as a link that's going to actually contain a button that's going to say share your work right if we're logged in then we indeed can share our work and this is going to be a link imported from next link and it's going to have an href equal to forward slash create project so it's just going to navigate us to another page so we can share our work now if we're not logged in then we'll need to render something known as auth providers so let's do that immediately let's create auth providers self-closing component so let's go to our Explorer and create a new component called auth providers.tsx we can run refce inside of there go back and immediately import it by pressing Ctrl space and then have it right here from dot slash this is great now you can see user photo and Share work but if we switch this to null you'll be able to see a link that's going to say auth providers which is later on going to allow us to log in this is great before we come back to implement the logic for this let's go ahead and move back to our footer to have all of these good links that are going to allow us to learn a bit more about our application so going to the footer component we can turn this into an HTML5 semantic footer tag and give it a class name equal to flex start as well as footer if we save that you can just see some gray Banner right here but let's create a div within it this div is going to have a class name equal to flex Flex Dash coal gap-12 and W Dash full for full width within that div we're going to have another div and this one is going to contain this portion which is going to be the logo as well as the overview of what our application does so we can give this div a class name equal to flex items Dash start and flex stash call there we can render a self-closing image tag and we can of course import image coming from next image and we can give it a source equal to forward slash logo Dash purple dot SVG a width of 115 pixels a height of 38 pixels and an ALT tag of flexible if we save this we can see a different version of our logo and below it we can have a P tag that's going to have a class name equal to text Dash start text SM fond Dash normal margin top of five and Max W Dash XS for Max width and there we can copy what we have here which is a text that says flexible is the world's leading Community for creatives to share grow and get hired great now we can continue with other parts of our footer so immediately below this div we're going to create another div and this div is going to have a class name equal to flex Flex Dash wrap so it wraps on mobile devices and gap-12 within this we're going to render a special component called footer column and this is going to be just a utility component or a helper component if you will that we can Define right here at the top so const footer column just a simple react component with an immediate return there we can return a div that's going to have a class name equal to footer underscore column we're going to have an H4 which is for now going to have a class name equal to font semi-bold and it's going to say title below it we want to render a UL that's going to have a class name equal to flex Flex Dash coal and GAP Dash 2 as well as fond Dash normal within it we'll be able to render some links so now if I save this I want to pass some data to this footer column I want to pass it a title and this title is going to come from constants as well so we can start typing footer links and immediately it's going to recommend to import it from add forward slash constants which we're going to happily accept so now we can say footer links 0 dot title and we also want to pass it a second prop which is going to be links equal to footer links zero dot links and this is the first time that typescript started being angry you can see it saying type title string link string is not assignable to type intrinsic type because property title does not exist on type intrinsic type what does that mean why are we using typescript and why is it messing with us right now well typescript is good in the long run it's gonna help you it's gonna cause you some frustration but it's your friend so right here we can just Define what we need we are accepting a title and some links and we can say those things are going to be of a type column props and then right here we can define a type of column props and say that the title is going to be a string and links is going to be an array of strings something like this not strings rather just the string and now you can notice that it's not complaining because we're passing exactly what we want so for the title we can utilize it and make it Dynamic so it's going to say four developers and for the links we can Loop over by saying the links.map and then for each individual link we want to return a link component like this that's going to have an href to just forward slash and a key equal to link inside of there we can also say link of course we have to import link from next link and we don't need an import for react if you do that we can see all the links and if you're wondering where is this coming from you can control click the footer links and you can see that this is just first out of many links that we have in these constants the reason why we do this is because if you develop this site and you want to share it with a person that is not a developer it's going to be easier for them to go through this modify it than to browse through the code that's the first reason the second one is you can easily switch this to a CMS so you can update the values using a Content management system and the third reason is why have all of this text in your code files keep the code here and keep the other stuff where it should be great now you might be still confused why did we create this footer column and extract it above well let me tell you below that footer column we're going to create a div and this div is going to have a class name equal to flex dash one Flex Flex Dash coal and gap-4 inside of there we can essentially just duplicate the footer column two times like so and the only thing we have to do is change the first one to one and the second one to two and we're going to immediately get two different sets of links right here you can see higher developers and Brands and we can just keep this going I'm going to duplicate them one more time and move it below this div we just created and I'm gonna say three that's gonna add another one and finally we can duplicate this entire div paste it below this one change it to four and five we're just creating some different structure with different amounts of links and finally we can duplicate the last one below that div and it can be footer links six it might look a bit crowded on a smaller device but thankfully we have a flex wrap turned on but on larger devices and on real established web applications they usually have a lot of links that they need to Showcase so this is looking pretty good to me right now there's a lot of information that we are covering great with that said the last part we have to do is to add this flexible All Rights Reserved copyright and the number of projects that the users have submitted and that's going to fill in the rest of the page so to do that we can go below this div and Below yet another div and create a div that's going to have a class name equal to flex between and footer underscore copyright inside of there we can say A P tag and we can say at 2023 flexible All rights reserved there we go and finally below that we can have another P tag that's going to have a class name equal to text Dash Gray and within there we can create a span that's going to be a class name equal to text Dash black and font semi-bold there we can say something like 10 214 and then outside of the span we can say project submitted later on we can make this Dynamic but for now this is cool and now we have the entire nav bar and the footer and believe it or not we can close all of this good stuff and we can immediately close the layout as well because we're done with it and we can be back at step one where we started which is on the home page but now of course with all the other good stuff that's here I hope you understand how cool this is because the layout does all the work it doesn't color your home page and we know where we left off but now with so much more than what we had before so with that said let's proceed but now we start with the real deal we'll start creating the models functionalities and relations to create the full stack capabilities of our flexible application to create all of these projects enable project detail pages and more and we're going to do all of that using graph base you can click the link in the description down below to visit graph base new redesign landing page damn does this look good the only thing you have to do here is Click sign up on top right you can sign up to graph base using GitHub and click create project here it's going to ask you to deploy a template one of many great ones or to import your Repository in this case we haven't yet created our own repository with a minimum graph based configuration setup so let's do that right away within our Visual Studio code we're going to open up the terminal and then click this plus icon right here to open up a new one then we're going to utilize graph base new SDK this is going to allow us to really quickly configure craftbase using typescript or just a regular graphql schema so we can immediately initialize a new project by running MPX graph base init dash dash config Dash format typescript and press enter this immediately created the project for us and we can find a new schema at forward slash graph base graphbase dot config.ts right here so inside of here we have some things imported for us and we have a general structure for every single application of a post a comment and a user just as examples but here in the docs we can read that g is a schema generator and config is the final object to return then we're just creating all of these types followed by the name and the fields and then we can create models using the model method and finally export the default config it is as simple as that the config is also going to allow us to connect the auth provider but more than that later for now we can remove all of these demo models from here to start from an empty slate we're just going to leave the config which for now we can clean up a bit as well and there we go we're gonna have two different models we're gonna have a model for a user so const user is equal to g dot model and then we can create a user and then we can pass an object of all of the properties that the user is going to contain that's going to be g dot string dot length so you can even specify some additional properties such as a minimum length of two or a maximum length of 20. whatever you want it is as easy as that because you have this handy utility functions that allow you to create your models next we can add an email and this email is going to be g dot string and then dot unique don't forget to call these as functions then let's do an avatar URL which is going to be a photo g dot URL let's add a description equal to g dot string and if you want to you can also add a minimum length right here then let's add a GitHub URL because maybe later on we want to modify our profile to include our own GitHub URL and we are going to make this optional because not every user has to have one we're going to repeat the process with a LinkedIn URL with g dot URL and then dot optional and most importantly we're gonna have projects and that's going to be a g dot relation but for now we're going to leave that relation empty because we have to connect it to something and that's something is going to be Khan's project is equal to g dot model project and then we can start giving it properties such as title is g dot string and we can do something like dot length of minimum of three let's give it a description equal to g dot string and now that I think about it we're going to also need an optional for the description of the user because not every user is going to have it so I'm going to add an optional tag right here it is so simple and if you hover over it you even have an explanation of what each property does it is as simple as that then we can have an image for each project which is going to be g dot URL we can have a live site URL we're creating a developer site so you'll be able to share your Project's live urls we're going to have a GitHub URL as well that's going to be g dot URL and we're going to have a category so every project is going to belong to a category which is going to be g dot string and then dot search this is going to allow us to search through the categories and then we can also have a created by which is going to be a g dot relation to the user we write that like this this means that the post or the project is created by the user but the user can have multiple projects so we can say project and then we can say dot list because it's going to be a list of projects and it's going to be optional because as soon as they create an account they don't yet have a project and with this we have our two models as you saw no additional setup we just created Properties or models based off of which we'll be able to create all of these great projects and right now you cannot even see how powerful this is but let me show you graph based Pathfinder this allows you to see that immediately as soon as you create these projects you can immediately query them so the queries are created for you as well as mutations so you won't have to create all of these functions to delete update or create projects yourself you just have to define the models and everything else is created for you but more on that later for now it's good to know that we have our projects we're exporting our schema and this is looking good for now later on we're gonna also add auth the reason why I wanted to have this here is because now we have a minimal directory that we can deploy to that we can publish on GitHub and then based off of which we can create a new graph based project so let's do that right away you can go to github.com forward slash new and create a new project and feel free to call it however you want to I'm gonna do graph base flexible feel free to make it public or private and click create Repository then you can open up the terminal and we can simply copy the commands needed to publish our repo such as get init git add Dot get commit Dash M first commit git Branch M Main get remote ad origin and then git push you origin master or in this case Main and in a couple of seconds our new repo is up which means that if we go back to graph base and search for graph based flexible or however you named it it should be right here there we go and we can immediately import it now it's saying that the schema is not recognized here because we didn't use a schema.graphql file we use their typescript configuration so this is automatically going to be present within your project so nothing to worry about and let's simply click deploy in just a second the project is created and you can see this connect button so let's click connect and we have the API endpoint and the API key which we can use from within our project so create a new DOT EnV file in the root of our directory and there you can create a next underscore public underscore graph base underscore API underscore URL and make that equal to to the API endpoint and below that we can create a next underscore public underscore graph base underscore API underscore key and that's of course going to be equal to our API key great for now we can close this and we are good to go later on we're going to explore this Pathfinder which is going to allow us to introspect the schema and see everything we have but immediately you can see that our project collection project search and all of these great queries and mutations have been created for us just by the fact that we created these two models within graph base dot config.ts isn't that great now that the main config has been set up we can go back to our project close everything and go back to where we started which is app and then page or rather we have to go to our navigation bar because inside of there we're going to start implementing our auth providers which are here using next auth and connected to graph base we of course need to First be able to log in to be able to create posts so let's go in that order forward our auth providers are going to be a use client component which means that they're not going to be rendered on a server and that's because we'll have to import the used State as well as use effect hooks coming from react whenever you're using any kind of hooks you cannot render it on the server because they leverage client-side functionalities so we can also import something known as get providers as well as sign in coming from next auth forward slash react like so now inside of here we have already defined our auth providers function so why not also declare a state by saying use State snippet and let's call it providers set providers and at the start we can set it equal to null just like so and since we're working with typescript we can also modify the type of our provider by using this notation right here and then within it we can say that's going to be of a type providers or null because at the start it is going to be set to null and what are providers well let's define that type right here at the top by saying type providers is equal to and it's going to have an ID equal to a string it's going to have a name equal to a string as well a type equal to a string a sign in url equal to a string a callback URL equal to a string and then finally sign in url params equal to a record of string and a string or simply undefined so now we're just constructing a provider not a providers type right here and the sign-in URL params is also going to be optional now we can create the multiple providers which is going to be equal to a record that's going to contain a string and a provider and all of this is just coming from the way that next auth structures they are providers I'm sure that if you dive deeper into the docs you'll be able to find this exact notation right here to specify the type of our providers now we want to check right here within the code if we have access to any providers so here we can say if there are providers of course in lowercase in that case we want to return a Dev where we're going to take the object that values of each one of our providers and then we're going to map through them so do a DOT map where we get each individual provider that's going to be of a type provider and then we can return something that something is going to be a button and this button for now can be just a regular button that's going to say provider dot ID so later on we'll be able to see what it is and since we're mapping over it we can also get an index right here and then set that as a key to a button right here if we now save this we won't be able to see anything because now our navbar things were logged in so if we go all the way up and switch this session to null which means that we are not necessarily logged in at the moment then you should be able to see a button that's going to say sign in there we go we cannot see anything yet but that's because we haven't yet populated our providers so for each one of our sign-in options we should be able to see one provider so how do we fetch them and what are those providers well to fetch them we're going to use a use effect hook so we're going to Define it to make a call just at the start once we load our component like so by setting the dependency array to be empty then we can create a function const fetch providers is equal to an async function where we say const res for response is equal to a weight get providers and as you can see this is coming directly from next auth and then what we want to do is we simply want to set it to the state by saying set providers is response and then we of course want to call this fetch providers function right here now if we save this what we can also do is cancel log the response to see if we're getting something back so console.log we're going to do a res right here and we're going to open up the console since we're on the client side we're going to get this console log in the client side usually on the server side you'll see it right here within your code so for now let's just reload the page and hope something's going to get back to us and we get a next auth client fetch error unexpected token yeah it's not really giving us a lot of information just that we don't have a valid client so there are still some things we have to set up for our next auth to work properly if you visit nextdash auth.js.org and click get started you're gonna see that you can install next odd which we already have done and then you need to create a special function or a special API endpoint within Pages API auth and then this special url.js so let's do exactly that we're going to go to our API and create a new folder inside of there called auth within auth we're going to create another folder with square brackets dot dot dot next auth and then within that folder we're going to create a new route.ts file so that should look like this app API auth next auth and then route dot TS and within there we can do something like this we can say import next off from next Dash auth then we can import some options but for those options we're going to create a special folder within our file tree that's going to be called lib as in library there we can keep some stuff some stuff like for example session.ts in this session we're going to keep all the data about the currently logged in user so inside of here we can import the get server session coming from next Dash auth forward slash next then we can also import the next auth options as well as a user coming from next Dash auth we also have some adapters so we can import a adapter user coming from next Dash auth forward slash adapters and hopefully all of this will make sense really soon and finally we have import Google provider so now we're coming back to those providers coming from next Dash odd forward slash providers forward slash Google is going to be Google and then we can also import the Json web token package coming from Json web token as well as import JWT from next auth forward slash JWT so we have a lot of imports and I can notice that they don't fall into one line so I can even expand this a bit further so we can make it a bit clearer to see there we go so as you can see we have all of these packages within our session.ts and now within this file we can export const something known as auth options which is going to be of a type next auth options and equal to an object this object is going to have a provider's array and inside of here we can Define all of our providers in this case we'll be using our Google as the one and only provider so inside of here we'll have to pass in our client ID which for now we can leave as an empty string and we'll also have to pass in our client secret later on we're going to get those values from Google next we can go below providers and we can create a JWT which is going to be an object here we're going to deal with the encoding so in code which is going to be a function as well as a decode process of our JWT or a Json web token and you're going to immediately see that typescript is going to tell you that we need to return something so this is going to use to override the method to control the next JS issued JWT encoding and this is going to be useful to connect the next auth to draft base the v-code function is going to be an asynchronous function and both of these functions are going to have the secret and the token being de-structured within their parameters and you can immediately see this because typescript is really smart so it knows what is it accepting it's also expecting us to return something but more on that later for now we're just creating the main structure our authentication can also have a theme so we can set up a theme of a color scheme equal to light as well as a logo which is going to be set to forward slash logo.png and then we come to the most important part of our entire configuration or odd options which is the callbacks so right here we can say callbacks and there we have a couple of important things we have the async session function inside of which we can destructure the session and that's a function that's going to get triggered every time a user visits the page and there we can just start a new session for the user then we're going to have another special function async sign in this one is going to be used whenever the user signs in we'll be able to get their information right here within the user object that's going to look like this and of course all of these now are going to give us a lot of typescript errors but soon enough we're going to fill in all the data to make it work for now we have the basic structure and we're exporting our auth options so we can go back to our route.ts and inside of here we can import auth options coming from add forward slash lib forward slash session there we can say cause Handler is equal to next auth and then pass in those odd options and finally nextgs is automatically going to allow us to export Handler as get and Handler as post this is going to allow us to make get and post requests using next auth great so the route is done but now we have to go back to the session and finalize all of its functionalities connected to graph base and connect it to our user models so that once we actually sign in using this authentication process the user is going to be created in graph based database that's why it's taking a bit longer we're not just doing a single sign-in we're going to also create a user later on and keep track of their Json web token what we can do now is get the client ID and the client secret for our Google provider and we can get to them by going to console.cloud.google.com there you can choose one of your active projects or you can create a new project let's go to new project and it looks like I've hit a project limit so I'm going to use one of the projects I already have but for you you can create a new project once the project gets created you can open up the navigation menu go to apis and services and then oauth consent screen here you'll have to just go through the application here you'll just have to select the app name the email authorize domains that's about it and click save and continue for all screens the type of the application can be external and then you can go to credentials and click create credentials and then choose oauth client ID the application type is going to be a web application you can enter the application name and then we'll have to add Uris this is going to be HTTP colon forward slash forward slash localhost 3000. and then for the authorized redirect Uris you'll have to add the HTTP colon forward slash forward slash localhost 3000 forward slash API forward slash auth or callback forward slash Google don't worry I didn't just think of this this can be found within next auth documentation for the Google callback you have to do it exactly like this for it to work so let me Zoom this in for you so you can see it better localhost 3000 here and then forward slash API forward slash auth forward slash callback for slash Google and click create this is going to give you a client ID which you can copy and then we can move them to our envs so if we scroll a bit down you can create a new Google client ID which is going to be equal to this and then also the Google client secret which is going to be equal to the client secret of course and you can paste it right here great we got everything we needed from Google Cloud now going back in here in our session we can actually utilize those environment variables so we can say client ID is equal to process Google client ID or an empty string or I think you can also do an exclamation mark that way it's going to know that it could be undefined as well and then we can do the same thing for process .env dot Google client secret like so and we're done when it comes to Google now for now I think we can even comment out this JWT because we just want to see it work and we can kind of just add a bit of code to our session and to our sign in because these are the most important ones so our session will have to return the modified session so for now instead of there we can simply say return session and I think this already should get rid of the typescript error of course we're going to modify that session much more later on and then for the sign in to work we can specify what is it accepting of which type is this user by creating a column here and then specifying the type of user is a type of adapter user or user so again we're making a differentiation between just the Google user and the user that we're going to have in our database and then within here we're going to have a try and catch block where we're going to try to get the user from our database if the user exists right get the user if they exist if they don't exist we're gonna create them and finally we're going to return true or return the user they exist right we're locked in if something goes wrong we're going to get the error which for now we can leave with type of any and we can simply console.log error checking if user exists or just error and of course we can return false because in this case something went wrong and we can really return true here because then typescript is no longer going to complain so this is the Bare Bones functionality of setting up the next auth but of course it's this connection where we're going to actually get the user from the DB or create them in the DB what matters because this allows you then to attach the projects to those users I hope that makes sense for now if we reload the page you cannot see anything yet so let's go back to auth providers and here we're showing the button and there we go it just appear the provider is Google so that's the provider id and we can actually see it so already this is a step in the right direction so for this button to work we also have to add a handle click function to this button so a handle click is going to just call the sign in function which is coming directly from next odd and this is simply a client-side method to initiate a sign in flow or send a user to the sign in page so inside of here we simply need to pass in the provider question mark dot ID because we have to sign in with that specify provider now if we save this and reload the page and try to click Google nothing's going to happen let's open up the inspect element and the console tab and click Google one more time and as you can see nothing really happens we do have a warning right here saying that type children is not assignable to type detailed HTML props handle click does not exist on the button of course I made a mistake here it's going to be an on click later on once we pass it to a custom button component we're going to call it handle click so immediately you can see Google we have all the information to sign in it has our callback URL and our sign in url so let's test it out I'm going to click Google and it's gonna show me the accounts I can log in with so let's select JavaScript Mastery and just like that we're signed in but we cannot really see that anything happened we can just see Google here that's not the right approach right so for now just to be able to verify whether we're locked in we're using this dummy variable of session but now we can actually try to utilize the session and see if it's going to give us real data true for Locked In Falls for not locked in so to do that we have to go back to our session for a second and create a utility function it's going to be called export async function get current user just like so and the only thing this is going to do is it's going to say con session is equal to a weight get server session like so and we're going to pass in our auth options we can also specify a type as session interface this is something we have to specify to know the type of our session because later on it's gonna matter what are we actually having in there so for this to work we have to create that interface or rather we have to import it from add forward slash common dot types it's coming right from here and if you want to see what that is essentially it's going to extend the session and then add these additional properties from Google such as ID name email and the Avatar URL which is our profile photo great so now if we scroll down we know how the session looks like and we can simply return the session now once we have this function we can go back to the nav bar and I think you already know what to do we can just say con session is equal to a weight get current user and we're going to import this from the add forward slash lib forward slash session and for this to work we have to make this snapbar function async and yes with next.js13 you can do that because it's a server-side component and it can be rendered asynchronously so you can do top level await that's pretty cool right so now we're getting this user and you no longer see the login button because we're locked in even though we're not getting the user photo at this moment we are indeed logged in so let's simply render that user image so we know that we're actually logged in and you can see it's complaining a bit right here saying that hey this condition will always return true since this function is always defined did you mean to call it instead this is pretty good it's typescript is immediately telling us hey this is not good so we want to do question mark dot user only if user exists then we want to do something but now it's complaining that the user doesn't exist on the property session and that's because I haven't called it here so you can see how typescript can come in really handy when you make stupid mistakes like that and not only it is good it exactly knows what this user is going to have so if I try doing something stupid like user.photo like this or rather session question mark dot user question mark dot photo it should automatically complain and it does property photo does not exist on type user so this is why typescript comes in handy when you make mistakes when you don't know what you have it's super useful sometimes it's annoying but in most cases It's Gonna Save you please comment down below right now pause this video and let me know if you'd like to see more typescript videos in the future or maybe even a complete typescript crash course or a typescript pro course just let me know down below great now that we have this let's simply render a self-closing image tag like so of course after we import it from next image which we already have and let's pass it a source which is going to be equal to session dot user dot image then we're going to also give it a width of 40. and a height of 40 as well and the class name of rounded Dash full and an ALT tag equal to this is going to be session.user.name and you can see the source is complaining right now a bit saying that the source should be of a type SRC set but it could be undefined sometimes so we only want to do this if this actually if the image exists so we can take this session user image and right here we only want to show that image if it actually exists so if we do session.user.image of course if we conditionally render that not to break the entire application and then we can render this only if it exists I think this should help us get rid of that error there we go as you can see now it's going to render it only if it's 100 sure that it exists there we go and let's invent it properly now you can see it says Google right here so let's try to re-log in and now we can see the Google again so something with the session is not going 100 true so we can focus on finalizing our session right away by going to get current user and then all the way to our session this is what we said we're going to finalize once we have the main functionalities for the sign in so this brings us to a really interesting part which is our first interaction with graph base and the database because we have to check if the user exists which is a get request and then if they don't we have to create them in the database so how are we going to do that well let me show you within our library we're going to create a new file called actions.ts and within those actions we're going to import something known as graphql client which is coming from graphql Dash request then we're going to create a new function const make graphql request which is going to be a function we're going to reuse quite a lot for every single thing which is going to accept a query meaning what do we want to query from the database and then variables if there are any which by default can be set to an empty object and we're going to have a try and catch block where if we have an error we can simply throw that error and then inside of here we'll have to actually make a connection to our database by doing something like client dot request but what is that client well a client is going to be a connection to our graph based database so we can Define the client above by saying cons client is equal to new graphql client and we need to pass in our API URL of course this is going to be different for production than it will be for localhost so at the top we can immediately start making our application both localhost and production ready which we can do by saying const is production is equal to process dot EnV y dot node underscore EnV node environment is triple equal to production and I want to take a moment here to let you know that what we're doing right now is writing a lot of code for sessions for actions for auth providers but this is necessary if you want to build an application that is real and actually usable usually on YouTube you see a lot of applications just you know try to put something up so you have the Bare Bones functionality but here I wanted to show you how you would do it in a real application for a client or for within your job so let me show you how to create that environment first you have the production then you have the API URL which is going to depend on the production so if we are in production then we can render the process.env dot next public graph base API URL or an empty string so our typescript doesn't complain or in other case it's going to be HTTP Colin forward slash forward slash and now we have to connect to our local graph based environment let me show you how to do that here you can run MPX graph base don't forget to use that 0.24 if you're in Windows and then you can write Dev this is going to spin up a graph based Dev environment as you can see it gives you an endpoint that you can Target so we're going to copy this endpoint right here and then paste it right here HTTP 127001 4000 graphql on top of the API URL we also need to have the API key so const API key is equal to if is production then we want to do the process.env next public graph based API key or empty string or usually it can be anything it can be some kind of variable that says let me in right here and you might be wondering where are we getting these environment variables from well remember before we ordered the hook top our application to graph base our repo and then we got these variables we got the next public graph based URL and then the key as well and we're connecting to them on our deployed environment but we're testing here on our local one so just so you know this is how it works and also we'll have to ensure that our server URL is correct so we can say server URL is equal to if we are on production so if is production in that case we're going to have process.env dot next public server URL which is going to be the URL of our deployed website or it can just be localhost 3000. once again I know this is a lot of setup and if I expand it in full line you're going to see this is just essentially four lines right but it needed to be done so we can properly make all requests no matter whether we are on localhost or on the deployed environment and now we can pass in our API URL so we know where our graph base is situated we can call its endpoints so now we have access to this client and within this function we can say return a weight client dot request we're going to pass in the query and we're going to also pass in the variables like so and I'm going to expand it even further so it fits in one line and this is it now remember where we were we were all the way in the session and we want to create one query in one mutation what a way to start working with graph base and graphql want to create and one post so let's utilize our newly created function to make those requests the first one is going to be export const get user which is going to accept an email which is going to be of a type string and then it's going to return the output of the make graphql function to which we have to pass two things and our typescript already knows that the first one is query and the second one is variables so what is going to be the query to get our user that's a question are we going to write it here the entire query to get the user well not really again I'm teaching you all the best practices to make your code scalable so what we can do is we can create a new file called graphql or rather a new folder right here we're almost getting to the end here so that's going to be graphql and then within that graphql folder we can create an index dot TS file and within here we can write all of our queries so we're going to export const a get user query which is going to have a backtick so we can write it in multiple lines and we can expand it like so every query starts with a query in the first couple we can write by hand but then either I can give them access to you or you can just go to the graph based Pathfinder and create them there much more easily than writing them by hand so how does it go query get user and then we're going to use graphql variables where you specify in variable name and a variable type like this and then you can use it within your query we're querying for a user and we're going to query by email so we can say email is going to be access to this variable of email and then we need to specify what do we want to return for that user we want to return an ID a name an email an avatar URL a description a GitHub URL Maybe as well as a LinkedIn URL everything we defined now how did I know to form this query in this way well first of all this is just regular graphql but graph base can help us even there if you open up the terminal and go to Pathfinder go to this URL right here just for the fact that we have already created our models remember before inside of graph based graph based config right here immediately within the Pathfinder you can create a query you can form it so we can go to the user query user user or in this case we can use user collection if you want to get more and we can pass the arguments by and then you can return to things such as name email and all that good stuff this essentially formed the query for you you can simply copy it and then paste it here and we're going to use this much more later on you can also use the user collection to get multiple users now we can go back and we have our first query so going back to actions we can actually make a request to make graphql request and pass in the get user query of course we have to import it from add forward slash graphql that is at the top right here and then we have to pass some variables in this case the variable is going to be an object containing an email like so great so how does this work this query and the variable gets passed to make graphql request which then makes a client request to our API URL which is connected either to our local graph based environment this one or the deployed one great and then what are we returning while returning a user containing all the things that we have defined within here the ID name email Avatar URL and so on so right here we can actually use the action that we created so we can say const user exists is equal to a weight get user what do we have to pass you already know what user question mark dot email right we're going to pass that as a string and then the output of that is going to be as user question mark user profile so this is a type of that user and we have to import this from common types and of course we have to import the get user from dot slash actions so now we have everything we need the user profile as well as actions great now it wouldn't really make sense to test if this works right because we don't have any users now so let's focus on the second scenario if the user doesn't exist let's create them so we can say if not user exists that user then we can await a call to create user and of course we have to create another action and another mutation to be able to call this so now we know the drill we have created the actions file and within here we can Define another action and this action is going to be export const create user hopefully you can see why are we making our code scalable Now by having all of these different folders because it all makes sense once you get to understand it within our create user we want to have a couple of props such as name of string email off string and Avatar URL which is our photo of type string then based on that we want to say const variables is equal to an object where the input is equal to what we want to pass such as name email and Avatar URL and this allows us to do the same thing we did before make a graphql request right here at the bottom where the query is no longer going to be get user query rather create user mutation so now we can go back to graphql index DS and we can create our second query or in this case mutation of the day which is going to be create user mutation so export const create user mutation is equal to a pair of back text again we can write this one by hand by saying mutation is create user where we get an input and the input is of type user create input so everything needed for the user creation and we can say user create where we take in that input that we passed as a variable and we want to return the user and the user is going to contain the name email Avatar URL description GitHub URL LinkedIn URL and of course the ID now we can go back to actions here we can call the create user mutation and of course we need to import it from add forward slash graphql and then as variables we're going to Simply pass variables because we have already formed them right here at the top hopefully this makes sense now we have the create user action and the get user action now back in the session right here we can call this a weight create user which we need to import from that slash actions and to it we need to pass the user.name as a string we also have to pass the user.email as a string and we have to pass the user dot image as a string as well this is all we need to form this and it looks like I didn't type as here we can also put this in new lines so it's just a bit easier to see something like this and once we create this user we want to just return true because we're getting it immediately later on from the server session so with that our sign in is done as well but now we have to return a session that doesn't just include the Google user the data we have there but also paired with the data that our actual user has I hope that makes sense let's take a moment so we don't want to Simply return a Google user what is a Google user well the Google user just on things like the name email in the Avatar URL right but now we want to hook up our Google user with our own database user which also has its own projects maybe it has its description or something else LinkedIn URL GitHub URL a lot of that gets tough right so we want to connect the two and make the session return the connection of the two so we have both the stuff from Google such as the Avatar URL for the photo but also we have the projects which we need right so to be able to do that we're going to populate this session to merge the two users to do that we first need to get the email by saying const email is equal to session question mark dot user question mark dot email as string then we can open up a new try and catch block and say Khan's data is equal to a weight get user this is the function we have created as user question mark is of a type user profile so immediately know what it is and then we can form a new session by saying const new session is equal to an object where we spread the original session like so we tap into the user portion of it we spread everything from the session user but then we spread everything from data question mark that user so this is the part where I told you about connecting the two it is a bit crazier annotation but hopefully if you know spread operators you understand what we're doing here we're creating a new session where we take both parts of the data or of the user and finally we don't want to return a session anymore we want to return right here within the try a new session okay and here for the catch I will just leave a console log saying something like error retrieving user data and then paste that error right here and this session is always expecting to return a session so even when we have an error we can return session right here maybe it's going to be an empty session but we have to return that okay we've made a lot of progress right here so we have the Google provider connected the theme the callbacks even two actions already connected to a graph base related to users in the future videos if you'd like me to use clerk to simplify this process significantly just let me know down in the comments I'm really looking forward to using it great but before we finally make this truly work there's one last part we have to do and that's the JWT encode decode and the connection to graph base of our account so let's focus on that final part of the auth and then we'll be able to get into the good stuff of creating all of the posts so let's go right here into our craftbase.config DOT yes and here we'll also have to connect our authentication so we're already importing auth at the top so going just a bit down below our models we can say const JWT which stands for Json web token is equal to auth dot all caps JWT and we have to create our issuer so the issue here is going to be graph base and then we have to add a secret every jwd has to have a secret and this secret is also needed for next auth so if you go to environment variables of the configuration part of next auth you're going to see that we need two things next auth as well as next auth secret and the secret is used to encrypt the next rjs JWT and to Hash the email verifications token so how can we create this next odd secret well let's search for it right here next auth secret and hopefully if we go maybe here no it doesn't tell us a lot but if we go to the next one next odd secret and go here you can see how we can create a good value for this secret they don't recommend just using something like I don't know what do we have here secret right not like that they recommend us to use the open SSL to create a random base64 32 character string so you can simply copy this Command right here or we're going to type it out together don't worry about that but you can go to open SSL online so I found this cool thing or if you're in Mac or Linux just type it into your terminal but on Windows is not supported so go to crypttool.org the link is going to be down in the description and then simply paste it right here and click enter and you're gonna get your own next GS secret next you can copy it like so and of course you could paste it here but it's better if we put it into envs bear with me you want to put it within the graph base folder and then.env so here you can say next auth underscore secret is equal to this right here and then within graph base you can read it by saying g dot EnV next auth underscore secret okay and we also have to add it to our regular EnV so right here below Google we can say next auth secret is equal to that thing and also we need next auth URL this is important for next auth to work that's going to be for now HTTP Colin forward slash forward slash localhost 3000 and later on in production environment we're going to switch this to make it a real deployed URL one now that we have this JWT we can use it within the config by saying auth is equal to an object where we have the providers equal to JWT and we can set the rules the rules is going to be a callback function that has the rules and then returns rules dot private which means that we're setting all the functionalities of our app to be private but then we can modify different models to have some different rules so right here our user we need it to be publicly read so everybody can read all of our users so that's going to be that auth right here where we have the Callback function of rules and then you can return or rather just specify rules Dot Public dot read but the situation is not going to be the same for the project where we want to say dot auth where we get the rules and then we specify rules that public dot read which means that everybody can see the posts but not everybody can create update or delete them so we can say rules that private dot create dot delete and then dot update like so there we go so now we have special rules right here and here and you can notice that our typescript is complaining a bit about the type so for this one we can just add a TS ignore and we can also add it here this is just for one lines because we're not really using these variables later on we're using them to create the models so with that said we now have the auth and the jwd connected we have our next auth variables everything is good and we're back to the final part of the equation which is to set up the JWT we need to encode the token and decode the token this is a good practice to learn a bit more about jwts and how do they work jwts are web tokens are the standard method for representing claims securely between two parties you can decode them verify them and generate them here's how it looks like the first part of the JWT contains the algorithm the encryption algorithm and the type of the token then you can pass any kind of data securely such as the name or any other ID and then you have to verify it and here the secret that we have is the secret to verifying it okay so if you want to share it you can but then to decoded the other person has to have your secret okay so let me show you how we can go back to creating encoding and decoding processes for the jwts I'm going to uncomment this and first we want to get the encoded token by saying const encoded token is equal to Json web token which is that package DOT sign and then we want to pass it an object where we simply spread our current token we set the issuer as graph base and then we also want to give it an exp or an expiration date usually people do map that floor date dot now divided by 1000 and then you can add plus 60 times 60. now I don't feel like doing the math right here and then you want to go out of this right here of the object and then passing the secret that's going to look like this now I don't even know how much time this is but I know someone that knows of course it's her friend Chad gbt so we can just ask how much time this is and hopefully they're going to let us know okay even though it's the current time and date but yeah it's saying 46 800 seconds how much in hours hopefully it's gonna give us a response okay it's 13 hours so this is kind of a standard but of course you can make it longer you can make it shorter it's completely up to you now that we have the encoded token we want to Simply return it because this is the only thing that this function does so return encoded token now we want to create a function that decodes it so cons decoder token is equal to Json web token.verify where we pass in the token first and we need to add this exclamation mark for typescript and then we pass in the secret and it's going to be as JWT so we can simply say return decoded token and believe it or not we're done with our sessions and creation user process and we are ready to close all of these good tabs and come back to our localhost application I'm gonna even dare to close these files and just go back to where we are which is here clicking this button that's going to actually sign us in so let's sign in using Google I selected my email and unfortunately got access denied you do not have permission to sign in so now let's debug it and figure out what this is all about it is possible that we have to reload our application because we have of course updated our environment variables so let's just reload it and rerun npm run Dev and we can return to localhost 3000. great let's give it another shot and it didn't go through one more time let's go ahead and check out our console here it looks like we have a client error unknown field LinkedIn URL it's supposed to be LinkedIn with a capital I right here did you mean LinkedIn URL thankfully the error handling is pretty good so we can now search for that LinkedIn URL and we can notice that we're mentioning that right here within graph base where it's mentioned in a good way but here we're trying to fetch it I need to properly spell it out so if I do this this is just one part but I doubt that this is the thing that messed with that auth but just to be sure let's try to sign in one more time yep as I supposed the same thing again but hopefully we have another error here we have a error saying that unauthorized access to mutation user create missing create operation so it looks like we weren't successful in creating the user but that's because we got our access denied by the oauth provider which is okay we wrote a lot of code of course there are a lot of issues so we'll go step by step with fixing all of them there's one really important thing which is the primary reason why we even created all of these things in the first place and connected these users in the sessions let me show you what it is by closing all the files and starting slowly going back to lib and then actions as you know inside of here we're getting our user and we're creating our user and later on we're going to do many other things here that not everybody should be able to do or should be allowed to do so we have a really robust security system here we don't want to expose any unnecessary variables some requests will be made on the client side where we really must be careful not to expose the key and some will be made on the server side so what we need to do is before we make this graphql request we have to add our API key to be able to make these actions so here in the get user we can say client dot said Heather of X API key is going to be the API key that we have defined right here above there we go and we can repeat this procedure for create user as well right here client that said Heather API key X API key this should get us one step closer to fixing the issue we have so let's go ahead and test it out by going back to localhost and trying to sign in once again and this is a good sign believe it or not even though it's another error it's a good sign because we progressed further it's saying that we're trying to access an image from Google and nextgs is not allowing us because we have to add this hostname here which you can copy we have to add it to our next JS config so copy this hostname go to next.config.js and then there expand this config and say images and then say domains and there you can add a string of lh3.googleusercontent.com and now if you save this we'll have to restart the app or it's going to do it for us and you can reload the page just to be sure I'm gonna press Ctrl C and then Y and then I'm gonna rerun the application by running mpm run Dev and in a couple of minutes we should be live on localhost 3000. if everything goes according to plan of course and we are live and we can see our profile photo as well as the button to share our work this is great this is not clickable yet so let's now go back to our nav bar and inside of here we can take our profile photo and we can actually make it point to where it needs to point to which is going to be our user profile so I know this took a long time but now we're properly creating all the users getting all the tokens and all the keys and everything we need to get to be able to create projects which is going to be our next step so we can wrap this image in a link right here this link is going to be of course a next JS link so let's properly do it there we go the link needs to have an href that's going to go to forward slash profile forward slash and then session question mark dot user question mark dot ID like so and immediately it became clickable and if you click it you're gonna get a 404 but you can see it is properly navigating to profile and then this special user ID this is great and if you reload the page you're gonna see hey we're still logged in which means that we're persisting our session and right next to the Share work we can add another button right here that button is going to be of a type is equal to button it's going to have a class name equal to text Dash small like this and then it's going to have an on click property that's simply going to say sign out and we have to get this sign out from next auth react so we can import sign out from next auth react like so that's great on click sign out and the button itself can say sign out and unfortunately we get to one really really important error in new nexgs 13 applications which is essentially saying hey any kind of clients have functionality such as on click you need to consider converting the part of this to a client component so whenever you get this you might want to consider extracting some of this code into an additional component that way you'll be able to keep the entire nav of our server side rendered while only this part can be client-side render where the combination of these two is going to allow you to interact with browser functionalities while at the same time allowing you to have everything else server set rendered for efficiency so what we're going to do instead here is we're going to create a new component instead of this image and everything else so here we can remove this image for now and just render the profile menu self-closing component so instead of this button and instead of this entire session with the profile we're gonna just render a profile menu self-closing component and to it we're going to pass a session is equal to session like so we can create this profile menu by going to our components and creating a new profile menu dot TSX and since this profile menu is going to contain everything we have created already it's going to be linked in that same GitHub just down below so you can just copy it and paste it right here you're going to notice that it's nothing more than just a simple pop-up that's going to tell us some information about our user alongside the image which we have already seen before so for now you can simply find it in the GitHub gist and then put it right here and of course this is a use client component so now if we go back you can import that profile menu which we have created save it and now we have that same image but with a new code we have just some image in a larger format the name as well these all here are some dummy URLs right now the only one we'll be using is the profile one to get to the profile page and then we have the sign out which if we look into the profile menu is doing exactly what we've done it has a button that calls the sign out functionality but now it's no longer complaining because this is rendering on the client side so we can use the US client I hope this has been a great lecture on kind of how to divide the server-side functionality from the client-side functionality great and then of course this now points to profile as before which we don't yet have and then Share work points to create project which we also don't yet have so the application after all of this work is looking still pretty simple but we have implemented such comprehensive and secure best practices for utilizing API Keys tokens user creation sign out functionalities all of it is there and it's just waiting for us to start creating those posts so now continuing with categories posts and load more would it make more sense because we don't have anything to categorize we don't have any posts and we cannot load anymore because we don't have any right so what we can do is start with the Share work page this is going to be a special page in xjs that we can create right here with an app create a new folder because nextgs is doing file based routing called create project and then within it we're going to have a new file called route.dsx and then inside of it we're going to have a new page.tsx file we can run rafce instead of page we're going to call it create project and we can also say create project here and we don't have to import react so now if we save this and Click Share work immediately will be redirected to this newly created create project page we didn't have to do any special routing or things like that such as in react immediately it got created just since we created this create project route this is great create project coming next to get started with the create project page believe it or not we're going to turn it into a modal we are doing an application similar to dribble after all aren't we so when you look at the details of a specific project it opens up a model on top of the current website same thing for create so we're going to simulate that as well what we can do is we can turn this div into a modal component like so and within it we can render an H3 element that's going to have a class name equal to model head text and it can say something like create a new project there we go and right below it we'll be able to render a project form component project form which is going to be self-closing component and for now we don't have to give it any props but of course we have two undefined components that we have to create so to do that let's go all the way to components and create a new model dot TSX component where we can run refce and let's also create the project form component.tsx where we can run rafce now going back we can import them by double clicking and then pressing Ctrl or command space and that's going to immediately bring them from add four slash components forward slash modal and project form and now we can see the model so what do you say that we immediately dive into the model and start implementing it our model is going to be a use client component so right here we can say use client usually you don't have to do this at the start you just start writing it out if you can make it a server component that's great but if you notice that using any kind of client-side or browser capabilities like for example use callback like use ref or like something like use router which comes from next navigation all of these things are browser specific so we have to turn it into a client-side component and of course these are coming from react and we're going to also add a type of react node later on we're going to also use the image so we can import the next image or rather just image from next forward slash image now our model is going to accept some children so right here we can say children and we can define a type for that children where children is a react node like so and what do we do we can just create a div within that div we can have another div that's going to show the children be needed right here so now we're passing a text create a new project and here we can see it within the form or rather within the modal but on top of the model we want to create some kind of an overlay so we're going to create two different ref properties the first one is going to be const overlay is equal to use ref which is going to be of a type HTML div element and at the start it's going to be set to null we can duplicate that and for the second one we're going to create a wrapper use ref which is also going to be a div and a null finally we'll need to use the use router to navigate to different pages so we can say router is equal to user router and we can do this because we're in a client-side component so now we can attach the ref to our div of overlay and we can give it a class name equal to modal and we can give it an on click property which is going to be handle click so now we can Define that function what's going to happen once this is clicked so we can say const handle click and we can Define this right now just as an empty callback function as we're going to implement the logic as soon as we're done with the layout but there we go now you can see the overlay appear so let's add a button to close the overlay right inside of it so here we can create a button that's going to have a type equal to button it's also going to have an on click inside of which we're going to call a function called on dismiss and this is another function which we can create and just leave empty for now and we can give it a class name equal to Absolute top Dash four and the right dash 8 and within it we can simply render an image and that image is going to have a source equal to forward slash close.svg a width of 17 pixels and a height of 17 pixels as well and it's going to have an altag of close there we go so if we save this you should be able to see the close right here on top right because we positioned it like that wonderful now we can also give the div below a ref of wrapper and a class name equal to modal underscore wrapper if we save this we can now see our great looking model that has create a new project and a project form and now of course we cannot do anything by clicking these so let's implement the functionality Forge The Smiths it's going to be pretty simple we just want to call the router right here and say router.push and we want to go just to forward slash we want to go home so if we do this and click it it will redirect us to home it is as simple as that now I did notice that I got locked out but no worries I'm going to quickly log in but this is a good opportunity to remind us that we still have to implement this better looking sign in button but we're going to do that as soon as we're done with the project create page I signed back in and we can go to share work and you can see this is working perfectly and now we're going to do the handle click as well the handle click is going to work if we click outside of the model we also want to be able to close it so what we can do is we can turn this into use callback to make it a bit more efficient so on this Miss use callback and use callback will return a memoized version of the Callback that only changes if the input has changed so we don't have to redeclare the function every time we just have to redeclare it if this dependency array right here has changed and inside of there we're going to have a router again this is just to make our code more efficient and now we can do the handle click it's also going to be a used callback so we can wrap our entire function with it like so and then we can also give it a dependency array and that's going to be on this Miss and overlay once those two properties change we have to recreate it now we can open up and expand the function Block it's complaining because on dismiss was used before it was created so we can push it right here above and the handle click is going to make a check if e dot Target is equal to Overlay dot current and if the on dismiss exists if that is the case we're going to Simply call the on dismiss function that is it so now let's see where did we make a mistake it's complaining a bit I think we have to close these two in another statement and here it's going to be e.target which we're getting through params right here e as in event and E has in any type but e is actually going to be a react mouse event so here we can say e is a react dot mouse event like so and now if we go back and click outside it closes it the same way if we clicked this mess this is exactly how a modal should be working and now we have this great slate where we can create a new project form which means that we're now done with this modal we see to create a new project and now we have the project form to this project form we're going to pass two props the first one is a type this form is going to be of a type create because later on we're going to have one of a type edit and then finally we're going to pass a user session because we have to know which user is creating this post so to be able to know that thankfully we have implemented the get user function so we can say con session is equal to a weight we have to make the function async and xjs allows us to do that and then we can say get current user and call it as a function that is coming from add forward slash lib forward slash session and then if we don't have a user so if no session question mark that user then we simply want to redirect to forward slash because that means that we cannot create a post and we have to get this redirected at the top by saying import redirect from next navigation like so and if we save it it's gonna complaint about the model let's see why the model wanted an identifier let's see it wants children and children it has because it's here but maybe it's complaining about the session and the type here that's about the project form so yeah this is it so now it looks like it's complaining about a model but model looks good to me it's the session that we are not passing so let me try to pass a session right here and now we can see that it's still oh no it's good never mind that's it so now this is our model we have our H3 and we are ready to dive into the project form and start implementing the functionality to create our first project isn't that exciting first we can accept some props so we can accept what we know we're passing a type and a session so right here at the top we can define those props by saying type props is type of a type string as well as a session of a type session interface and if you remember correctly this is a common type that we created before so we can simply import it and then we can say that the props is of a type props to keep it clean right here and we know what we're getting and with that we can start with creating the layout of our project form of course we're going to wrap it in a form component like so our form is going to have an on submit property which is going to be equal to handle form submit which is a function we're going to Define just here within the component const handle forms a bit which is going to get an event which is a react event form and for now we can leave it as an empty function then we're going to have a class name which is going to be equal to flex start and a class of form if we save this I guess we have a typo here so if we fix it and then save it it says that we have an on submit function here which means that immediately we have to turn this into a use client function so let's do that right away and there we go we cannot see anything because we haven't yet started adding the fields to our form so let's do that right away within the form we're going to create a div and this div is going to have a class name equal to flex start and form underscore image Dash container then within it we're going to have a label and this label is going to have an html4 and this is going to be set to poster and then a class name is going to be Flex Center as well as form underscore image Dash label inside of here we'll be able to render the image if we are editing the form or the project but in this case we don't have any so I'm just going to type image or we can do something like this where we can say if image for now I'm just going to create a dummy image variable const image is null in that case we can say if no image in that case we can show something like choose a poster for your project or a thumbnail however you want to call it and then we get this cool view where we'll be able to upload our images so to implement the upload functionality we can add an input tag below and this input is going to have an ID of image a type of file accept is going to be image and then asterisk meaning all images required is going to be if type is triple equal to create then it's going to be true else it's going to be false and when you have a Turner like this you can just say type is create and a class name is going to be form underscore image Dash input and an on change is going to be equal to handle change image and this is something which we can again Define right here at the top handle change image it's going to be similar to this one but this is going to be a change event and it's going to come from more specifically it's going to be an HTML input element like so once you write a couple of these you're going to immediately know how to use them and all of these have to be imported from react so you can immediately import change event from react this is a type now you can see that this is complaining here an HTML for poster but where is it a poster and first of all this should say four and not form and the poster is going to be right below the input so this is going to be your actual image so we can say if image exists or rather this image is going to be on the form so we can immediately create a dummy form which is going to look like this it's an object where your image is going to be just an empty string for now so now we can say form dot image both here and here and if the form dot image exists then we can return an image it's going to have a source equal to form question mark dot image a class name equal to on small devices padding 10 object contained to keep the aspect ratio and z-20 to show over other content it can also have an ALT tag equal to project poster and a fill property and if you haven't already we have to import image from next image right here at the top great now we cannot of course see our image because we haven't yet uploaded one but soon enough we're going to do the logic for upload as well before that let's dive below this div and let's start creating the form fields for our project each one of these four Fields is going to be reusable so we can create a new component that's going to be called form field and we can share a couple of things to it we can share a title equal to a title a state of something like form dot title then a placeholder in this case the title of the project can be something like flexible and then a set State function so these are all some props that we haven't yet utilized but we're going to accept them within our component so here we can pass in a value and we can pass in the handle State change of title and value like so these are all things that we have to Define so first of all we have to Define what value is we have to define the title on the form and we have to define the form field itself as well as the handle State change a lot of stuff to Define but we can start one by one so let's scroll all the way up and let's create another function that's going to be cast handle State change that's going to accept a field name which is going to be a string and it's going to accept the value which is going to be a string and for now we can leave it empty here we know that our form is going to have a title as well so we can add it and now would be the time to create this component the form field component so let's go into components and create a new form field dot TSX run refce and we can now import it by double clicking and pressing Ctrl space or command space right here it is going to complain that it doesn't have all the right properties but now we know what we have to pass to it which means that we can go into it and start focusing on our individual form field that form field is going to accept a lot of different props we have to modify it in a lot of different ways after all so let's define the type for these props first it's going to be the type is it going to be an input or is it going to be a text area that's going to be a string then we can have a title which is a string then we can pass a state which is the value string we can also pass and I think I have to use semicolons here placeholder which is also going to be a string is text area we can also pass this as a Boolean and this means that it's not always going to be there so only in some cases and we can also have a set state which is a function that accepts a value and then it doesn't return anything so now we can accept all of these props by saying type title State placeholder is text area and set state and all of this is going to be of a type props and that means that we are ready to start creating the layout of this component so inside of here we can give it a class name equal to flex start Flex Dash call W4 and gap-4 immediately within it we can create our label and this label is going to have a class name of w Dash full text Dash gray Dash 100 and it can say something like title and if remember from the last time we passed the title of title to this one then we can check is this a text area element if it is then we can render a text area element or most likely it's an input so we're simply going to render an input tag right here okay so text area or input in this case it's going to be an input now to both of these we're going to pass some similar properties such as placeholder is equal to placeholder or state is equal to state and value is equal to state they're going to also be required and they're going to have a class name equal to form underscore field Dash input and finally they're going to have an on change equal to where we get an event and then we set the state to e.target.value we can copy this text area or rather just its properties and put it into our input tag below like this and let's see if we miss anything we also have to specify the type of the input so it can be either the type that we provide or it can be just a regular text input so now if we save this you can see that we get our first great looking input right here with a placeholder and everything else now this was a lot of work just to do one input you might say right well not really because we're going to use this or reuse it to create many many many more other inputs so what we can do is we can duplicate this input a couple of times maybe even three or four or five so if we save this you can immediately see all of these great looking inputs although they're the same right so what we can do is we can change this one into description the state is going to be formed that description placeholder is going to be showcase and discover remarkable developer projects and the value is going to change the description we have to be careful about what we change then the next one is going to have a special type of URL and it's going to say website URL it's going to be form dot live site URL and the placeholder can be something like https Colin forward slash forward slash jsmastery dot Pro feel free to put anything you want and this is going to update the live site URL property the next one is also going to have a type of URL it's going to be a GitHub URL this time so GitHub URL the form that title is going to be GitHub URL it's gonna say something like https colon forward slash forward slash github.com and I'm going to put my name here you can put yours and the here we can say GitHub URL you have to ensure that this name here and this string right here are the same that's the only way that it's going to update it later on later on right below we're gonna also add a custom input for the category but more in that later and finally at the bottom we're going to have a button so here we can create a div that's going to have a class name equal to flex start W Dash full and there we're going to render some kind of a button that's going to say either create edit or something like that so if we save this now you can see how much better this is looking we immediately have all the fields that we need to have it seems like we don't have a lot of space between those though so if we dive into each one of these let's see if we have properly put all the styles we have a form underscore field Dash input that's looking good to me and here we have a flex start Flex call W4 and GAP this is indeed looking great and these inputs are within now this div but rather the flex start form div so this is looking good to me of course we can make some tweaks later on to make it look even better for now let's focus on doing this custom input or custom menu for the category of our project which is also really important so here we'll be able to create a new component called custom menu and we're gonna pass it similar things things like title of category state of form that category we're going to also do filters which is going to be equal to category filters which is coming from add forward slash constants if you check this this is simply an array of all of the different categories that we have in our project and then a set state which is going to be similar where we pass the value and then we have handle State change category and then the value right here great now we can create this new component of custom menu dot TSX and run refce we can go back and we can now import it right here and for now we won't be able to see a lot because it just says custom menu but if we go into it we can start implementing it in a similar way that we implemented our inputs to implement it we're going to import a menu coming from add headless UI forward slash react and we're going to also need to import a fragment coming from react as well as an image of course coming from next forward slash image and we don't need an import to react now let's remember which props do we pass into it title State filters and set state we can copy most of these props already from the form field component so go there go back to custom menu and Define the type of props where we're going to have the title state we don't need these but we do need a filters which is going to be an array of strings like so and we have a set state which is the same as before so now we can simply accept all of these props by saying title State filters and set state which is of a type props there we go and we can start creating it we're going to start by wrapping everything in a div and that div is going to have a class name equal to flex start Flex Dash call W Dash full gap-7 and relative within it we're going to have a label for this field and this label is going to be an html4 this specific field and it's going to have a class name equal to W-4 text Dash gray Dash 100 and it's going to render the title immediately below the label we're going to have a menu and this menu is going to act as a div so we can say as div and with a class name equal to self-start so this is going to align self on the start and then relative within this menu we can have a div and this div is going to render a menu dot button that menu button is going to render either the state which is the category or we're going to say select a category if none have been selected before we can now save it to see how does it look like and there we go we have selected category which doesn't do much yet but we can style it by giving it a class name of flex Center and custom underscore menu Dash BTN this style is going to make it look like a toggle and we can also add an image right here that's going to have a source equal to forward slash Arrow Dash down DOT SVG with a width of 10 and a height of 5. It's a small icon it's an ALT of arrow down but it's going to signify that you can actually click this and see more options now below this div we're going to render a menu dot items in this menu items is going to have a class name equal to flex start as well as custom underscore menu Dash items and inside of there we can render the filters by saying filters.map we get each individual tag and we can return something instantly so just parentheses here for each one of these we're going to return a menu dot item and that menu item has to have a key because we're mapping over it which is going to be a tag and within it we can render a button that button is going to have a type equal to button a value equal to tag of course dynamically right the one we're passing a class name equal to custom underscore menu Dash item and then on click equal to an event where we set the state to be equal to e dot current Target dot value current Target because this is a button within the menu item and not just a regular input and within the button we can render the tag itself so now if we save this and click select a category you can actually see the menu appear and you can close it and open it and you can see all of these great categories and for now you cannot select them or you cannot even type anything in these fields but you will be able to do that really soon once we start managing it within the state and it looks like we didn't even need this fragment so I can remove it right here now we can go back to the project form and you can see we have a lot of these red things which means that we're not properly assigning them within the state yet and we also don't need this extra form field I think I created one too many so the last one is the GitHub URL so what do you say let's create a real State and not just a dummy field right here to manage all of these properties to do that we can say use State and then select use State snippet call it a form in the set form and at the start we can set this equal to an empty object but we're going to pre-fill it with empty values such as title is an empty string description is going to be an empty string as well this way typescript is going to know of which type each one of these properties are image is going to be an empty string as well live site URL empty string GitHub URL an empty string and a category an empty string and we of course have to import use State coming from react right here so now we have all of these in the state but we're not yet updating the state if you think about it this handle State change function is not yet doing anything so let's make the logic of our form work and then we're going to finalize this create button and actually hook it up to our graph based database and using graphql functions and actions we're going to create our first project in our database exciting stuff ahead we have the state for our project we're going to also create one additional State just the helper state to know whether we are currently submitting the form or not while it is loading so we can call it is submitting set is submitting at the start can be set to false then we can modify the handle State change to actually update the form by saying set form since we're going to update the form using forms previous values we need to create a function out of it call it prev form or prev state and then return immediately return by wrapping it inside of parentheses and then an object where we spread the previous state like this and then add the additional field name and its value like so let me put it in the new line so you can see it better so set form pref State field name and then value this is going to ensure to immediately return it and update it great now of course before we can actually utilize all of these values we have to implement the functionality for uploading images to cloudinary that's going to allow us to serve and host those images there on their servers and they're going to provide us with a URL that we can utilize to then send over to our database so let's get started with that by diving into our handle change image function we're going to separate it a bit from the other functions and start by diving into its function block there first we want to call E dot prevent default which is the default behavior of the browser to reload the page we don't want to reload it then we want to get access to the file that a person will upload by saying const file is equal to e.target.files and then zero in this case we can also add a question mark dot here because maybe it doesn't exist so just to be sure if we don't have any file then we can simply exit then if not file.type dot includes an image meaning it's something else in that case we want to return an alert that's going to say please upload an image file if we have a file and if it is an image then we can say const reader is equal to new file reader we're going to read the data as data URL and pass in the file in there and then we need to unload that reader by saying reader dot unload it's going to be a function where we want to get the result of that reader by saying reader that result as a string and then we want to handle the state change or we're going to update the image to the result that we get right here and then later on when creating the post we're going to take this and we're going to pass it over to cloudinery to upload it to their servers as we discussed before now let's compare this create a new project with the deployed application one you can see there's just a bit more space between each and every input and everything else is basically the same so yeah we're really close to being done but of course let's first figure out the spacing between those items so that's going to be right here where we have a form field and these form fields are contained within Flex start form it's going to be a flex start not flexed start so as soon as we fix this it's going to look much better and we can try uploading our first poster so I already have a couple let's choose one let's go with this nft backdrop and you can see the image appear right here which is looking great finally we can type something like nft's landing page of course you can do something else we can do a description you can also do a URL so that's going to be something like this it has to be a real URL so I'm going to just do nfts.com same for GitHub and then you can choose a category and then we have a create button so all of it is ready but let's focus on modifying our create button to look just a bit better and we can do that by creating a new custom button component which we're going to reuse many times throughout the application so here let's render a new button that button is going to of course be created within the components folder button.tsx and it can be an rafc e just like so to that button we can pass a title property title something like create we can also pass a type equal to submit it's going to have a left icon if it is submitting so if it's submitting then we can do nothing so empty usually it can be a plus icon so plus that SVG meaning hey add something and then it can have a state of is submitting is equal to is submitting based on that we can modify the default disabled state and the button can be self-closing because immediately we're going to render whatever the title says right here and now we can dive into the button or rather we can import it by just pressing Ctrl space or command space and then importing it at the top coming from dot slash button as soon as we do that we will be able to accept all of these props and show them on our new beautiful button so to be able to do that let's dive into the button and let's first create the props or the types for all of the props we're receiving that's going to be a title of a type string a left icon which sometimes might be there sometimes might not and that's going to be either a string or a null then we can have a right icon same thing goes for that we're going to have a handle click sometimes and that's going to be a mouse event handler and that's going to come from react so you can import it at the top then we're going to have a submitting property or is submitting property which is going to be optional and it's going to be Boolean we can have a type which is going to be either button or submit like this and we can have a BG cooler later on which is going to be optional and it's going to be a string and finally a text caller if we want to further modify this button this is great and now we can accept all of these props right here by listing them one by one such as title left icon right icon handle click is submitting type BG caller and text caller and all of these are of a type props and this will be a regular button but of course we're gonna style it to look like a great one so let's start doing that right away by passing all of these props to our regular button such as a type of either type or a button a disabled state which is going to be equal to is submitting a class name equal to flex Center gap-3 PX4 and py3 and finally an on click which is going to be equal to handle click I'm just going to leave a comment here for us that later on we also have to change the VG cooler and text cooler as well so yeah these are to be added later on great and finally within the button we can show our left icon of course only if it exists then we're going to render an image that looks like this where we're going to have a source of course equal to left icon a width of 14 pixels a height of 14 pixels and an all tag equal to left we can duplicate this right below name it a write icon source is Right icon and I'll tag is right and then finally we can render the title itself right here and we need to import images from next image now when we save this this is going to look much better than before and that is it of course we can style it further with colors and things like that but for now we are good we have our own great looking button now this button is going to change what it says depending on are we currently creating editing or doing something else so here we can complicate this title a bit we can say if is submitting then also if type so like this within the curly braces if type is triple equal to create then we want to open a new ternary and say creating or in other case we can say editing right and then outside of this ternary we can have another one again check if the type is triple equal to create and if it is then we're going to say create else we're going to say edit I hope this makes just a bit of sense we still need to kind of explain it so let me put it in multiple lines if we're submitting we want to check if we're currently creating in that case we want to say creating or editing because is submitting is true but then we want to go out of this meaning something like this where we want to close this one here and dive into the second ternary right here and then we want to again check if type is create in which case we just say create or edit not creating or editing because we're not submitting at this moment and of course we have to fix those little things such as such as the mistakes we have with closing the parentheses and in situations like these I get pretty lazy so I just say hey fix this and then it pass the code chat GPT is really good for for simple things such as this one and it even formats it nicely so we can just put it here and you can see what I meant so you'll see later on how this is going to say creating or editing or create or edit and I think when we're looking at the finished site when I said how good the button is looking so it's not looking that good yet so we still have to apply some additional styles to it so this is where the BJ caller and text caller come into play so right here we can just add additional class names by turning this class name into a dynamic template string like so we can put it into a new row and then say if we are submitting so if is submitting then we can pass the opacity of 50. then we can change the BG black 50 like this else if a BG caller exists then render the BG color else render the BG Dash primary Dash purple like so and we also want to add additional things such as rounded XL and text SM text Dash SM edium and on Max MD W-4 so this is going to be a full width on medium devices if we now save this we have a better looking button but still we can change the text color so here we can say if there is a text caller that we provide then use that one else just use a text white like so and I believe this can be shortened to just text color or text white same as this here BG cooler or BG primary purple and there we go now we have a great looking button and we have create a new project so now almost everything is done besides our handle submit function so inside of this handle submit right here is where the magic is going to happen inside of here we're gonna call some of the actions and actually make connections to our database using graphql calls so let's make that happen next inside of here we're gonna also have to do the E dot prevent default to prevent the reload behavior of the browser we're working with nexgs it should feel like a native app no reloads whatsoever then here we can start the S submitting process because we have started to submit it and then we can open up a new try and catch block if the type is triple equal to create in that case we can start creating the project by calling the create new project action so let's go to lib actions and then right here below create user we're going to create export const create new project that's going to be an async function that's going to accept a form of a type project form this is a type which we can import from common types at the top right here and then what we can do is also get the second thing which is the creator ID we need to know who is the person that created it and the third thing which is the token to know that that user can actually create that project and then we need to upload the image to cloudinery to do that we can say const image URL is equal to a weight upload image and we're going to pass the form dot image into it but clearly you can see that upload image is not defined so right here above create new project we can export const upload image which is going to be an async function that's going to get an image path which is a string as its first and only parameter and then we're going to have a try and catch block of course we need to turn this into an arrow function first from here we're going to write const response and we'll try to make a request to our own backend so we can say fetch and we want to go to forward slash server URL forward slash API forward slash upload and we can then pass some additional options into it but before we do that let's actually create this backend endpoint through which we're going to upload images to cloudinery to do that we can go right here at the top go to API and then create a new folder called upload within upload we can create a single route.ts file and within it we can start preparing our post route to create a route in nextgs the only thing you have to do is say export async function choose the type of the route which is in this case a post and then specify what is it going to get it usually always gets a request which is of a type request and then you can open a function block here to this function we're going to pass a path which has come from a weight request.json so this path is just something that we're going to pass right here through the options while making this post request then we want to check if a path exists or rather if it doesn't so if there's no path we want to return next response dot Json and then provide a message something like image path is required and we need to provide a status of 400. this is how we do things in nextgs 13. you have this next response which comes from next server and then to it you can provide a message and you can also provide a status but the way you form them is in two different objects first you have the message which looks like this and then you have a status where you can specify the number of that status and you can form it into a response that looks like this so this is a new syntax it's okay I I like it as well before it was a bit different but this makes sense but if we do have a path then we want to open a new try and catch block where we have a const options where we can Define our options and our options is an object where we're going to provide some additional information to cloudinery something like use underscore file name which is going to be set to true also unique file name set to false overwrite set to true and transformation so here you can transform the image before you upload it for example we can specify that the width will be 1000 pixels and a height of 752 pixels in a crop equal to scale this allows you to keep your images small and scaled exactly how you want them for your specific application finally we have to create an instance of cloudinery to do that we can import V2 as cloudinary coming from cloudinery and then we can run cloudinery dot config to which we have to pass a couple of things such as Cloud name as well as an API key as well as an API secret and of course we're going to get all of these things by logging into cloudinery so if you go to cloudinary.com you'll see that it is one of the most powerful image and video apis and you can go to the top and click sign up or log in once you log in you should immediately be greeted with all the variables that we need so simply press copy go here and paste them right there of the entire config has already been created for us this is great this is all that we needed so what we can do now is we can store these into environment variables so we don't expose them to the web so let's go to our EnV and let's go down and paste them right here of course we need to format them so that's going to look something like cloudinery underscore name is equal to we don't need string signs here then we're going to have a cloudinery underscore key which is going to be equal to this key right here and finally we have the cloudinery underscore Secret is equal to and then we have this secret right here of course for you it's going to be different now you might have noticed that for some variables we add a prefix of next public and for some like Google client or cloudinery we don't do you know what's the difference well the envs with next public will be accessible to the client-side application and the ones that don't have next public are going to be available only from your server endpoints and since we're calling this only from the server as well as the cloudinery we don't need to add next public great so now instead of these values we can just use environment variables by saying process.env Dot cloudinery name and we can keep it going we can duplicate the process in v this is going to be cloudinery key and then finally we can have cloudinery Secret great so now we have our own instance of cloudinery and we can use it alongside these options to upload the images to the server by saying const result is equal to a weight cloudinary dot uploader dot upload and we have to pass a path and the options and then we can return the next response next.json where we have a result as the first parameter not within an object and then we can have an object of status 200. and then if we have an error we can simply duplicate this say message is simply an error and status is going to be something like 500 server error or you can do something like cannot upload cannot create or anything like that but now we're successfully uploading images to cloudinery which means that we can go back to our upload image and we can finalize the call to this API upload endpoint that we created obviously the method is going to be post body is going to be Json dot stringify where we pass a path which is equal to image path and this is it finally we have to just return response.json which is going to contain the published URL of our image on cloudinerease servers and here we can just throw the error great and now back to the create new project now we have this published image URL and we can actually utilize it we can make a check to see if imageurl that URL exists if it does then we can make a request or return the output of the request to make graphql request bypassing the create project mutation we haven't created it yet and the variables which we also haven't created yet so now we can go back to our graphql mutations and queries by going to graphql index.ts and in here we added the two ones for the users but in the description Down Below in that same GitHub gist you'll be able to copy and paste the entire file for all mutations I explained it to you how it works before and I told you that you can go to the path finder to create them there even simpler so now just to simplify our process we're gonna just paste them and then I can explain each one here so as you can see we're doing a mutation create project or we have an input everything that we need to create our project and then we create it and finally just return the created project so now we can go back and import this create project mutation and we have to form the variables we want to pass to it so to do that we can say const variables is equal to an input where we first want to spread the entire form we want to append the image to it which is equal to imageurl.url and then most importantly we want to say created by and we want to link it so we say link to the Creator ID so now with all the data from the form paired with the image to the uploaded image to cloudiness servers paired with the Creator ID from the session we have everything we need to create a project besides one thing we don't have the permissions to upload it because who's going to say this user truly is logged in how can we say that just based on this Creator ID we cannot somebody else can just go to the specific profile copy the ID and make a false request but thankfully our app is ultra secure so we need to add an additional header client dot set Heather authorization and here we can pass the bearer token like so and this token we're passing from here so later on when calling this create new project function we can pass the token as one of the parameters we don't have the functionality to fetch the token just yet but we're going to do it soon because we're done with this create new project action so we can go all the way back to the project form and here we can make a call to this action simply by saying a weight create new project which is coming from at forward slash lib forward slash actions to which we need to pass a form we have to pass a session question mark dot user question mark dot ID and then we have to pass a token as well great so let's figure out how to get access to this token right here well to do that we're going to create a new function cons token is equal to a weight fetch token so what is this going to be and where are we going to put it that fetch token is yet another action so we're going to create it right here above the upload image by saying export const fetch token is equal to async function with a try and catch block where we want to get a response by making a request to bear with me fetch and now we want to Target our own endpoint by going to server URL forward slash API forward slash token or no it's going to be auth forward slash token this is where next auth automatically publishes your token by default and then once we get it we simply want to say return response.json or we want to throw an error I know we've done a lot of stuff but bear with me step by step we're gonna make it so we can look into this I think just by Googling it it should already give us some information about API auth token if we search for next auth and you can see that next auth exposes a rest API that is used by next client and then you can see this endpoint right here so yeah this is how we get the token using next auth now we can go back we can turn this function into an async function rather the handle form submit needs to be turned into an async function and we can import fetch token from lib actions so now we have the token where we we're passing all of this data to create new project and the ones or if we successfully create this project then we want to Route us back to the home page so now we can also Define the router at the top of the component by saying const router is equal to use router use router is of course coming from next forward slash router and then we can say router.push slash to go to the home to be able to see our post then if we have an error we can say something like console.log error this is going to be enough and then we can have a finally so this happens either way and here we can set is submitting to false to stop the loading great now you can see that the next router was not mounted this is the use router and we use the client hook right here so let's figure out why that is the case it looks like I made a mistake this is supposed to come from next navigation they keep changing that stuff so yeah just so you know use router comes from next navigation so I think we now have everything we need to create a project and I know we spent a lot of work on this but I want to let you know the majority of this project form if not even its entirety is going to be reused to create the edit project functionality so hopefully that makes you feel a bit better um great let's go ahead and test it out by creating a new poster here for the project I'm gonna do this finance app let's call it Finance Finance description we can do https column forward slash forward slash finance.com duplicate that here and select a front-end category and I want to open up the inspect element to see if something's going to go wrong alongside the network Tab and we can also open up the tab here to see if we have any console logs or errors and let's click create we can see the token and unfortunately we got a 400 for the token immediately this action with HTTP get is not supported by next auth so let's see how we have been trying to fetch that token if we go to the fetch token function we can see a weight fetch server URL forward slash API forward slash auth forward slash token and when I said it is automatically exposed by next art it's not fully we have some of the functions but we still have to create that endpoint right here so going back to the app API we can create a new folder with an auth called token with a new route dot TS right here and it's going to be a simple one don't worry so we can say import get token coming from next Dash auth forward slash JWT we can also import the next request as well as the next response coming from next server these are just some types we can Define our secret by saying con Secret is equal to process.env dot next auth secret remember we created this before and we can export async function get where the request is of a type next request and there we can get the token by saying a weight get token and we pass in inside of curly braces the request the secret and the raw is set to true there we go finally we can return a next response with a Json where the token is right here within the object and status is 200. so now if we go back and if we try to recreate this I think we won't be able to because it says creating right here now so we'll need to reload and then add all of these parameters one more time but that's not a problem let's do that right away again I'm going to type finance.com for all of these and I'm going to choose a front end and I'm going to clean the network Tab and the console tab so let's click create the token went through the upload to cloudinery hopefully goes through no we got a 404 on upload on cloudinery interesting and we did get a path to the image as the payload that we're sending over with it but we've been trying to make a request to localhost 3000 API upload post which wasn't found so let's see if indeed it is there API upload and then a post route so it is here it's weird how it wasn't able to find it localhost 3000 API upload yeah it seems good and maybe here we have some issues let's see I'm not sure if this is related at this point so we can just look into the error we have here essentially he's having trouble finding this route to the upload one way in which we can test it if it's recognizing it by exporting async function get and then in there simply returning something like return next response and we can return a 200 and we can also return something like hello from upload that way if we go to this URL in the browser it should allow us to check it out and as you can see it doesn't seem to be there so we're definitely doing a mistake when it comes to the routing of this back-end endpoint sometimes nextgs just forgets that we added new routes so it might be possible that we need to delete the dot next folder and then just rerun the application to see if that's gonna work let's give it a shot I'm gonna stop it from running delete the next folder yep and then I'm just gonna rerun it after doing so again it's a wild guess but while developing this application we encountered on a couple of these errors so these are the types of tips that I told you I was gonna give you in this video so let's try to reload the page and see if we're gonna get this hello from upload once it reloads if we do means we're doing everything good and nextgs is to blame if not we're definitely calling this route from the wrong place or in the wrong time and it looks like we do get a 404 so yeah I should be careful of what I say so one more time let's try to reassess the situation that's why we're here let's see where the error originated right now we're trying to get an API route by going to localhost 3000 forward slash API and then we go into forward slash upload and just get the get route out of it to be able to see something but that is not working so let's try to go to console or network and we can see a 404 here it cannot find that route in the terminal here let's see what's happening I don't see any special errors or anything really breaking so for now let's try to revisit what we tried to do before I'm going to remove this get I'm gonna go to I'm gonna close all the files for that matter to here to have a clean working environment and I'm gonna go to where we were which is the project form inside of here we were trying to fetch the token so we go into the fetch token and this makes a request to API auth token let's try to revisit the creation one more time I'm going to click create the token did go through I forgot that and then we got a 404 on upload so this is a post shroud on localhost 3000 API upload and we get an error on Project form line 35 so this is why it's important to have both the network Tab and the console open so on 35 this is just the console log yes because this thing broke but the upload is what actually broken which is right here on line 59 of create new project so if we go into it it's actually this because we're trying to access server URL which is a local host forward slash API which is here forward slash upload and we're making a post request to it so we have to go to app API upload route and then look into this post route right here it's saying we have 400 but that shouldn't be the case because we do have a post route under this specific route and we are actually returning the next response with a status of 200. and after doing some light debugging I try to log in again because I got logged out and now I cannot even sign in what's happening let's try to figure it out together hopefully this didn't happen to you as well but if it did we're here to resolve it so we don't have almost any data here we don't have any data there we do have some data here in the console saying that LinkedIn URL on type user was meant to be LinkedIn URL with a capital I here so let's search for LinkedIn URL even though we've done that already so we have length in url and when it defined it it had a capital I right here and all the other cases we defined it as lowercase I so what I'm gonna do is I'm gonna just switch it right here where we defined it with a lowercased i that way it's going to be the same in the user type in the graph based config as well as in all the queries believe it or not one little detail like this can mess it up but thankfully we can see the console and the errors so now if we go back to localhost 3000 and we try to log in once again we are logged in and we can try to share our work hopefully for one last time so once again I'm going to select the project I'm going to type the title description the URLs and the category and I'm gonna click create and we're back to where we started where the upload unfortunately isn't being picked up by nextgs in here do we get anything useful we see detected multiple re-renders currently rendering the same context provider this is currently unsupported and the same thing happened a couple of times so let's try to track the errors we have two points of information right here the unrecognized post route is the first one and then this syntax error unexpected doctype in Project form 35 all of which we have already seen so let's go to the project form and here we're trying to call this and we have this error right line 35 so that definitely means that this one breaks the token succeeded because we can see it right here we have it successfully fetched token and the Creed project almost succeeded but the upload was the one that broke things When developing this application I just remembered that in the next config right here I also added below the images the experimental and then within experimental I added server components external packages and set that to be an array of cloudinery as well as graphql request and if you hover over it it's gonna say that this is a list of packages that should be treated as external in the RSC server build and you can find more information here but now if we save this I think it's automatically going to reload the application because of the changes and it's going to restart the server so now if we try to reload the page or rather restart the server one more time ensure we're signed in and then try to create a project for hopefully one last time I'm gonna stop saying that now and then I'll just type in right here finance.com and paste it multiple times clear this and click create and it succeeded this time graphql succeeded and we are done so it indeed was just this little thing that it needed to treat it as an external package in the build and if you go to the API docs you can find more information about it here dependence is used inside server components and Route handlers will be automatically bundled by nextgs if a dependency is using node.js specific features you can choose to opt out of specific dependencies from the server components by bundling the use of native node.js require and node.js includes a short list of popular packages but maybe cloudinery is not there and it needs to be there as well so it was this little detail that maybe was really really hard to find but as I said I went through the pain to be able to show you how all of this works so the post was created I mean we don't know right so how can we know well we can know by opening graph base right here and then going to the URL which is the Pathfinder right here so if we open it and go to Project collection select arguments of last 10 is okay and then try to get edges node and we can do the title in the description and click project collection you can see that we have one project right here successfully created and we can see all of that within graph base this is great and finally the create functionalities are now fully working which means that we can close all of these files and go back to the home page and finally start rendering out those posts on the home page great work to get started displaying the posts we can finally go back to the place where it all started our homepage page.tsx and inside of here you can see that we have posts so yes let's fetch them and then display them to start fetching the posts we'll have to create a new action called Fetch all posts of course coming from lib and then actions right here below create new project we can export const fetch all projects this is going to be an async function that's going to look like this we're going to pass two different things in the category which is going to be optional or of a type string and the end cursor this is going to allow us to know on which page are we on and this is also going to be of a type string great once we're inside of here we also need to immediately set up the X API key to be able to make a request like we did with this one so we can copy this client.set header and we can just put it right here then to fetch all posts it is as simple as returning the output of make graphql request where we make a request to projects query and we pass in the variables which is going to be the category as well as the nth cursor and we can import the projects query from graphql so now if we go back to the page we can actually import the fetch all projects coming from add forward slash lib forward slash actions and we can use it by saying Khan's data is equal to a weight fetch all projects and for now we don't have to pass anything in it it's enough that we call it and we can say as project search so this is a special type that we're going to create right here on top of our home so we always know what kind of data are we getting back from Fetch all projects so we can say type project search is equal to an object or we have the project search this is coming back from graph base we're gonna have edges inside of it which is going to contain a node and our node is exactly our project interface coming from common types so our node actually is one instance of our project and we're gonna get an array of the projects on top of that on top of the edges or rather next to the edges we're gonna also get some Page information such as do we have a previous page that's going to be a Boolean do we have a next page that's going to be a Boolean also the start cursor meaning on which page are we on right now and the end cursor as well so this is great now we can Define that type project search we have to import the project interface as well and we have to fix this typo right here as it is Project search we're also using a weight so we have to turn our home into an async function great and finally we're getting back some data from here so we already know how that data is going to look like because we have the structure the data is going to contain the projects but to get to those projects to display we'll have to do data question mark dot project search and then question mark dot edges or just an empty array so these edges contain the nodes which are considered projects so we can make a check and see if projects to display dot length is equal to zero then we can return a section that's going to have a class name equal to flex start Flex Dash coal and paddings and inside of there we're going to return the categories but we're going to also return a P tag that's going to say no projects found go create some first and we can also give a class name to this B tag equal to no result text and text Dash Center if we save this we shouldn't be able to see it because we already have one post so now is the time that we Loop over those projects to display instead of just simply saying posts and to do that we're going to create a new section and this section is going to have a class name equal to project Dash grid and inside of there we can map over projects to display dot map where we can de-structure an individual node and we can specify the type of that node to be equal to project interface we already know that that's our project finally we have to open up the function and then immediately return something and that something is going to be a project card self-closing component and of course our project card is not defined so let's go ahead and Define it immediately by going to components and create a project card dot TSX inside of there we can run rafce and then immediately import the project card within the page and we should be able to see something what do you think we're going to see well of course we're going to see one project card because there's one project although we're not showing any data right now we can pass it into that project card we're going to pass a key equal to something like node question mark dot ID we can pass an ID as well equal to node ID we can pass an image equal to node image we can pass a title equal to node question mark dot title we can pass a name equal to node question mark dot created by question mark dot name this is the creator we can pass the Avatar URL of the Creator which is going to be node question mark dot created by question mark dot Avatar URL and then finally the user ID so we can say user ID is equal to node question mark dot created by question mark dot ID this is great and I can see it's complaining about the ID yes because we haven't yet defined the type of props we want to pass into it so now we can move into the project card and Define all of the props that it's going to accept so we can do that right here at the top by saying type props is equal to we can pass an ID an image a title a name an avatar URL and the user ID all of which are going to be strings now we can get them by saying ID image title name Avatar URL and user ID and these are going to be of a type props of course now we can start creating the structure of our project so that's going to be exciting we spent a lot of time setting up the back end and creating the possibility to log in and to create projects and now we'll be able to soon see something that looks like this a bunch of pretty cool projects that other people have developed so let's do that right away here within the div we're going to give it a class name equal to flex Center we're going to also give it a flex Dash call and rounded Dash 2XL as well as a drop Dash Shadow Dash card this is going to make it seem like it's floating above other things immediately within the div we're gonna have a link component and that link is going to have an href property equal to forward slash project forward slash ID so if we click it we want to get to the project Details page we can also give it a class name equal to flex Center group relative W Dash full and h-4 and inside of there we're going to show our project image so that's going to be a self-closing image tag with a source equal to image and I just noticed I misspelled the title here so I'm going to fix that and we have to import the link from next link as well as import the image from next image the width is going to be about 414 pixels and height is going to be set to 314. I found those values to work the best we can also give it a class name equal to W-4 h-4 object Dash cover to remain its aspect ratio and rounded to XL finally we can give it an ALT tag equal to Project image if we now save this we should already see our great looking image or instead of that another next GS error this is a simple one to fix though we simply need to add resth.cloudinary.com under our approved image handlers so if we go to nextdad config.js under domains we can add res Dot clouddinary.com and allow it to display images from that source as soon as we do that and reload we should be able to see our great looking image and it looks like our app broke after changing the config so we're gonna rerun it that's not a problem and then we can re-render the next GS app little quirks and gotchas like these are okay as long as you get a phenomenal looking end product that is incredibly fast and efficient as it is with nextgi server side rendering so we definitely want to get the benefits so we gotta be okay with an occasional break and an occasional Quirk and feature and there we go we can see our great looking image immediately below the image we can render a div that's going to have a P tag inside of which we can have a title so immediately this is going to be finance.com maybe not the best title and let's style it a bit by giving this div a class name equal to Hidden group Dash hover and then flex and a profile underscore card Dash title and to this speed tag we can give a class name of W-4 now if we save it it should go within the image and this is looking much much better right now still we want to provide some more information about the person that created this post so we're going to go below the link and create a new div that's going to have a class name equal to flex between W-4 PX of 2 for padding horizontal and margin top or Mt of 3. font semi-bold and text Dash SM for small within this div we're going to create a link tag that's going to have an href property pointing to forward slash profile forward slash user ID like so so if you click the image you're going to go to the project details but if you click the name of the person who created it you're gonna go to the profile details and within here we can render our Avatar URL within a div so we can render an image and this image is going to have a source equal to Avatar URL a width of 24. a height of 24 as well a class name of rounded full and an ALT of profile image if we save it we should be able to see it right here there we go and this div can have a class name equal to Flex Center and GAP Dash 2. this is going to divide it from what's yet to come So Below this link now pointing to profile as a matter of fact we can pull this a bit right here so we can see what we're editing below this link we're going to have a div for some additional information it's going to have a class name equal to flex Center and gap-3 and within it we want to have a div that's going to have a class name equal to flex Center and a gap of two and there we can render an image that's going to have a source equal to forward slash hearth dot SVG I think it's a bit misspelled here but that's not a problem and then we can do a width of 13. and a height of 12 I think is what works the best and then I'll tag of Heart below it we can render the number of likes so maybe something like let's do 525 likes and a class name equal to text Dash SM if we save it you can see a number of likes and we're going to duplicate this div right below and we'll rendered the i.svg I right here and we can render something like 5.2 K and these are going to be the number of views so we have the likes and the views for now these are static but of course if you want to improve this application you can implement the commenting liking and viewing functionality that would be pretty cool of course below our profile we also want to show A P tag right here below the image of the name of the person that created the post that's what's missing so if we add it here this is looking just a bit better and also one cool thing that I've done is I've just asked chatgpt before to Generate random values for the views and the likes so it generated something that looks like this where we have two used states which we can import and a use effect and there it's simply called random likes random views which is set to zero and an empty string at the start feel free to copy this out and then within a use effect at the start it sets a random likes to a specific number for example map that floor mat at random times ten thousand and then for the views it divides it by 1000 and adds the K as 1K 2K 3K and so on and then provides a random number so feel free to copy this out and then you can use the random likes right here as well as random views at the bottom just to make the app a bit more Dynamic until we don't have the real data and if you do this and if you import the use State properly from react as I thought was the case we need to turn this into a use client component because we're using States so we can simply say use client at the top and then you can see some random numbers right here which is looking great of course now that the project card is done we can go in one of the two ways we can Implement more of what we can see on the screen here such as the categories or maybe more interesting part would be to implement the project Details page because right now once we click it we can see a 404 so to start implementing it we can create a new page that's going to be within app one folder called project and then within the project another folder called in square brackets ID and then within the ID folder the page.tsx which is going to be the project Details page so we can run refce inside of there reload the page and hopefully we're gonna see a page but now is our job to turn that page into a comprehensive project details section to get started with this page we first have to get access to our data so let's rename the page to project and let's try to figure out how can we get the data from graph base into this page well you already know the structure right it's going to be creating actions to graph base and graphql to fetch that data so what we can do is first we need to say const session is equal to a weight get current user thankfully we already have a function that does that it's defined in the add forward slash lib forward slash session and we can call that as a function and we can also turn the project into an async page once we have the session we can create a new action right here below the old one we can create an export const get project details which is going to get an ID which is going to be a string and there we can do something similar to what we did for just getting a project that's going to be here get user that that works as well we can copy this paste it right here below we need to set the x API key and then we can make a request to get project by ID query and we can pass the ID as the first and only parameter within our variables object and we can of course import the get projects by the query from add forward slash graphql you see how easy it is to add new ones once you have the structure put in place so now going back to here we can say const result is equal to a weight get project details when we pass ID and we can say as project project question mark because we won't have it initially is going to be of a type project interface like so and we can then import the get project details from the lib actions and of course the ID we have to get it from somewhere so where's the DNA come from well it's going to come from the params of the page notice it we have it here project and then the project ID so the way you get to that in nexjs13 is through params your de-structure programs and you can de-structure the ID from params and we can also specify the types so params and then inside of it we have an ID which is a string like so the project interface we also have to import from add forward slash common types great so now hopefully we have a result we can make a check for that result if no result question mark dot project in that case we can return a P tag saying something like failed to fetch project information but hopefully we won't see that we're going to see a page which means we're good so let's simply console log what do we have here console.log result question mark Dot project and now if we go to inspect and console we should be able to see nothing this is the important part we see nothing think fast why do we see nothing here because it's rendered on the server side there's no use client directive which means that we don't have to render it here rather we're getting the data here in the terminal so you can see the project the title description image livesight URL category and even old information of who created that page that's great so this is the most important part we have all the data about a project right here in the result.project and now the last part is to code something that looks like this where we have a modal that we already had before a simple header on the top rendering an image some short description with the links and then we're going to develop this special more buy section where we can show other projects by this user so the majority of this code is nothing special it's just taking all the data that we got right here and then displaying it on the screen in a nice manner so if you want to I want to give you a challenge right now take a step back and try to develop this try to use this data use Tailwind CSS properties and try to put a design like this in place with the links to the GitHub live URL image category and all that good stuff you don't have to do this part yet where we show other projects just this part where you lay out the data if you want to do that pause the video and do it right now if not or in any other case Down Below in the description in the GitHub gist there is going to be the finished page.tsx file so we can simply override what we have right now and paste it here you're going to notice there's going to be a couple of things that we don't yet have access to such as a couple of components like project actions or related projects so for now we can simply comment those out let's see project actions right here I'm going to comment it out you don't have to we're going to fix it soon and then related projects so if I comment these two out and if a comment out their Imports you can see what we have exactly what I told you we're going to have the intro we're going to have the category link the link to the profile the page the links description but now we're going to implement the project actions which allow you to edit or delete the post and related projects together so yes please do comment out this part line 53-57 and also part at the end because now we're gonna slowly start implementing these features one by one and that's what really matters let's start with related projects first we can uncomment it we're passing to it the user ID and the project ID and we have to create the related projects component so right here inside of the components let's create a related projects dot DSX and run refce if we do that and bring back the import at the top we should be able to see them right here yep but now they're just a simple component so how do we proceed with building those related projects well let's dive into the related projects component and let's implement it together to get started with the related projects we can immediately accept some props that we're passing into here such as user ID and project ID so let's first create the type of props is equal to user ID which is a string and a project ID which is a string as well I think at this point you can already start noticing many many of these patterns that we often do when creating these applications so we can destructure those props user ID and project ID and that's gonna be equal to props and I just wanted to take a moment and let you know that web development and everything in life in general is just pattern recognition the more work you do the more you're gonna start noticing patterns in that work and the more patterns you notice you'll be able to improve yourself in those patterns and then learn much faster because every new project is not going to be a new project it's going to be in one way or another similar to another project you've done and that's powerful that's actually one of the concepts we teach in the master class we teach you how to create a couple of apps with all of the best practices mental help and PR reviews and then you can go ahead and become a software engineer on your own because in a couple of years when you need to build any kind of application you're gonna have the foundations down you'll just have to reference to what you've already done I just wanted to put that out there but with that said even while watching this video you're learning immensely and improving your skills so now that we have this user ID we can use it to get all of the projects that belong to that specific user and to be able to do that we can create a new action So within actions we can duplicate get project details and instead of that we're gonna get user projects so here we can say get user projects we're going to get the ID we're going to also pass something known as last question mark So how many of these do we want to get that's going to be a number we get the API key and then we get projects by off users query and this of course has to be imported from graphql also we have to pass the ID and the last into this function then in related projects as you already know we can say const result is equal to a weight get user projects from lib actions pass in the user ID give it an Ask property user question mark is of a type user profile which is coming from of course our common types and we can also make this an asynchronous function because we're using a weight inside of it so now that we have that result and we know how a user profile looks like we know that it contains these things one of these things is projects edges and then node so we already know we have to dive deeper to get those projects so we can say const filtered projects is equal to result question mark dot user question mark dot projects question mark dot edges and then we want to filter them out so we want to say question mark dot filter we want to grab an individual node by destructuring it like this say that the node is of a type project interface which is also coming from common types so we can get the project interface right here and of course it's not a component it's just a regular type so project interface and now we have to close this of course so we have to return all projects that belong to this user besides the project we're currently looking at and we can do that by saying no with question mark.id is not equal to project ID okay so we surely have some typos here and errors so let's fix those together we have a DOT filter method right here where we get a node and it says right here cannot find node on projects did you mean node I don't think so it should be a lowercased one we need to close this function right here that's what I missed and then we return a node I think we're a bit better now yep I think this is good now so now we have the filtered projects and we can say if filter projects question mark.length is 0 with simpler return null and I hope you get what we're doing here we were just getting all of the projects that belong to a specific user but then we want to filter out the one we're currently on because we don't want to show it two times so if we do this we're looking good and now we can start with the section to show all of these projects so to do that we can create a new section give it a class name equal to flex Dash call margin top of 32 and W Dash full within we can create a div that's going to have a class name equal to flex between and a P tag that's going to say more by result question mark dot user question mark dot name so we want to see more by in this case I think it's going to be JavaScript mastery of course this P tag can have a class name equal to text Dash base and font Dash bold and below that we can also show a link tag that's going to have an href equal to forward slash profile forward slash result question mark dot user question mark dot ID and a class name equal to text stash primary Dash purple and then text Dash base and inside of there we can say view all so all the projects that belong to that specific user and now we can import link from next link with 1K of course let's see if it got imported there we go and if we save this and reload we cannot see anything yet so it seems like it's not getting the filtered projects let's simply console log them right here so console.log filtered projects and this is also on the server side so it's going to appear right here and it looks like it's an empty array it does seem like my JWT expired so let me see if that indeed is the case yep we have our Google right here and while we're here let's also fix that Google button so if it didn't log you out you can just log out manually and we can go back to the nav bar to make this button within auth providers look just a bit better so here instead of rendering a regular button we can render a button component that you can import from dot slash button pass it a key pass it a handle click property and then we can also make it self-closing like so remove the provider id inside of there and then simply give it a title equal to sign in if you now save this this looks much better I'm going to sign in again and I'm gonna visit this project one more time and we still cannot see anything below JavaScript Mastery so if we open up the terminal we can still see just an empty array so there must be something wrong with the way in which we're fetching the related projects let's see what that is about get user projects where you pass a user ID and then we say result user projects edges we filter out the node where node.id is not equal to project ID this is looking good so let's see if the get user project is looking good there we accept the ID and a last property we set the client header and then return a graphql request get project off user query and we pass in the ID and the last Yep this is looking good to me as well so we should be seeing a post but hey I think I'm stupid here we cannot see any other posts because this is the only one that we have created so what we can do is we can create yet another post from the JavaScript Mastery account to be able to see it on the home page so in this case we're going to do this medical application we can type medical app medical app description and then http colon forward slash forward slash medical.com and we're going to put it as a backend so later on we can check the categories let's see if the create is still working we are hopefully navigated to the home page and we can see the second post and now if we go back to the original one we still cannot see anything if we go to a new one yep there we go now we can see more by JavaScript Mastery and view all and if you reload the page it could show here as well yep there we go more by JavaScript Mastery view all so this is good that means that we actually have the project in place and that now we can continue to actually show those other projects So Below this div containing the link we can create another div that's going to have a class name equal to related underscore projects Dash grid and here we can simply go over the filter projects question mark.map to map over them where we get a node which is a project and it is of a type node is a project interface and there we simply return a function that's going to return one project and this is going to be really similar to a project card so we're going to have a div that's going to have a class name equal to flex Center related underscore project Dash card drop Dash Shadow Dash card within it we can have a link and this link is going to have an href property pointing to the project details so forward slash project and then node question mark.id of that project and it's going to have a class name equal to flex Center group relative W Dash fool and H dash full as well within it we of course need to render the image of that project so that's going to be source is node question mark dot image and the width is going to be 414 pixels and height is going to be 314 pixels the class name is going to be W Dash full for full width age Dash full for full height object dash cover rounded Dash 2XL and finally the alt tag of Project image if we now save this of course after we import image from next image we should be able to see one related project yep here it is we can also provide a title of that project and that's going to be right below the image by saying Dev class name usually hidden but on group hover like this we want to make it a flex and it's going to have a style or class of related project card underscore title like this within there we can render a P tag with a class name equal to W Dash fool and it can simply render the node question mark dot title like so if we do that and if we hover over it we can see medical app and we'll be able to see all the other projects created by this user right here Isn't that cool and that brings us almost to the end of the project Details page but let's not forget one thing and that is the ability to edit and delete this project as an owner you should be able to do that so that's going to be hidden within the section that only the user that created it can see everybody else will be able to see this but if we are currently the locked in user that created this then we'll have access to this component called project actions so let's move on to the actions next we can uncomment this part of the code and we can create this project actions component by going to components and creating a new projects or rather project actions dot TSX and we can run refce inside of there go back and then simply double click control space and then import now if we save it and go into the component you can see the project actions on top right because we are the user that created this post so what will these actions do well let me show you we're gonna get the project ID through props so we can say project ID is going to be of a type project ID is string right here then inside of it we can wrap everything in a react fragment and have a link the first link right here is going to have an href pointing to forward slash edit Dash project forward slash project ID so this is a special page which we're going to soon create it can also have a class name equal to flex Center edit Dash action underscore BTN and within there we can render an image that's going to have a source equal to forward slash pencil or I think here it's misspelled to pencile.svg and then we can do a width of 15 and height of 15 as well with an altag of edit now if we import the link from next link and image from next image we can save this and you should be able to see an edit icon in the similar fashion below the link we can render the button component and this button is going to be of a type is equal to button and we can copy this pencil paste it within the button and then just rename it to something like trash and this is going to be delete if we save this you can see a button that's going to render a trash can or it's white right now so you cannot see it so let's apply some styling by giving it a class name equal to let's make it Dynamic Flex Center delete Dash action underscore vtn and we can do something like BG Dash Gray if we now save this you should be able to see it right here and we can also create a function at the top called const handle delete project which is equal to an async function where we want to know are we currently deleting or not and for that we're going to use a use State field that's going to say is deleting set is deleting at the start set to false and of course we need to import the use state from react and we also need to mark this component as a use client because we're using a state then this button can now change the color depending on are we currently deleting or not so we can say if is deleting then the button can render BG gray like so and if we're not deleting then we can render BG Dash primary Dash purple just like so and of course we need to close it properly so I think that is right here if we now save it it's gone so let me see if I did it right so if we are deleting then BG Gray usually this is going to be BG primary purple like so there we go so this is already looking better and now we have to implement the logic for deletion it's going to be similar to Logic for creation so at the start we can say set is deleting to true to trigger that loading state then we need to get the token because this is one of the secure actions we have to do create update and delete for those we need to get the token but now it's easy to get the token by saying a weight fetch token and we have this function created within lib actions so we can simply import it from there then we can open a new try and catch block and we need to create a new action called delete project so moving back to actions right below get user project we can copy this get user project paste it below and rename it to delete project we need to get the ID of the project we're deleting as well as a token so we can say token is the second parameter of a type string instead of setting the API key here we need to set the authorization because this is one of the secure actions and let me see if we're doing that somewhere already authorization Bearer token I think we are in the create new project yes so we can copy the set header authorization Bearer token and we can paste it right here instead of X API key and then we make a return make graphql request to delete project mutation and we pass just the ID in of which project we want to create and we can of course import this from add forward slash graphql so now if we go back we can call the await delete project which is coming from lib actions and we can pass in the project ID as well as the token once we do that we can Define the router right here at the top by saying const router is equal to use router and we call it as a function and this is coming from next router so after we successfully the lead we just routed that push to the home page because the post is deleted otherwise we can simply cancel that log the error and we can also add a finally Clause where we're going to stop the deletion loading from happening and the use router is coming from next navigation not next router so if I fix this right here we should be good and now we can attach the handle delete project to the button by saying on click is going to be equal to handle delete project that is it so now let's try to delete one and edit the other so if I click delete right here it actually deleted it and redirected us to the home page great delete is working but the edit is going to redirect us to the edit page which we are yet to create so going back to app let's create a new folder called edit Dash project and then inside of there we can create a new page dot TSX believe it or not this page is going to be incredibly similar to create project so let's go ahead and copy the entire create project page and paste it into the edit project we can also rename it right here to edit project and let's save it once you've done that you can also rename this to edit project and we can change the type of the project form to edit let's save it go to the project and let's try to edit it as you can see we get a 404 because that's edit project and then the project ID so I missed one thing within the edit project we're not just creating it we already know which one are we creating so we have to create an additional folder to comply with this structure so we can create a new folder with square brackets and then ID and then within that folder we need to put the page this is going to make our routing work and you should be able to see a new page the edit page for our post there we go it says edit and we have the complete form that we had before and even the button says edit but one of the last things we're going to do is we have to populate or pre-populate all of the fields from the edit so that we can immediately edit them so it doesn't feel like we're creating a new one so let's do that next to achieve that we can use one of the actions we've used before saying cast result is equal to a weight get project details or pass in the ID and say we're going to return a project of a type project interface now we can import the get project details as well as the project interface and the ID where is the ID coming from well it's coming from params right here so we can get it right here by destructuring params and then destructuring the ID like so and we can say that that's of a type params that contains the ID that is of a type string and we have the result the result contains the project so we can now pass that over to the project form by saying project is equal to result question mark dot project and now we can go into the project form and we can accept that project right there by saying project we can add it to our props right here by saying project it's sometimes going to be there and it's going to be of a type project interface and now we have access to this project and what do we do we simply fill all of the values of our state so we have it here we can override or hold alt and then select the end of all of these strings move before them and then we can even hold Ctrl and then shift to copy all of the Words Press Ctrl or command C move back away and then type project question mark Dot and then paste it or an empty string this was a pretty cool little shortcut trick if you don't manage to do it like this in one try you can just type it out by hand but essentially what we're doing is we're saying title is project.title description is project.description and so on and would you look at that all of the values are automatically filled we can type them out and hopefully we can edit the project but now this wouldn't quite yet edit it because if we go to the submit form here we're looking at the type of create so what we need to do instead is we have to say if type is triple equal to edit then we want to call another function or another action of course that's going to edit it so we can go to the actions page we can duplicate the delete and rename it to update project like so we're going to accept a form which is going to be of a type project form as well as a project ID which is going to be of a type string and then finally a token of a type string now there are a couple of interesting things we have to do here we're going to set the authorization headers but we're going to do that later on first we have to check if the user has also redeployed their image or they kept the same image as before because maybe only the title changed so we need to check if the URL of the image is a base64 string if it is then it's a new upload if it's not if it contains cloudin array in there then it's an old upload so chat GPT can come in handy here we can ask it to generate a JavaScript function to check if a string is a base 64 data URL something like this and then we immediately have a regular expression that tests it feel free to do that test and it even shows you how you can call it I did this test before and it gave me something like this where you have is base64 data URL you pass in the value you use some regular expression and test against that value based on that we can know if it is a new image or not in any case we're going to create something known as an updated form inside of which we're going to spread our previous form then we can say const is uploading New Image is equal to is base64 data URL and we're going to pass the old image then if we are uploading the new image then we have to do the same thing we did when we were creating it which is const image URL is equal to a weight upload image form dot image and we have to make the function async of course and the project form of a type here starts with a capital p so now that we get the image URL we have to add it to the updated form by saying if imageurl.url updated form is equal to the spread of the form and then we exchange the image to the new cloudinary image once we've done all of that we set the headers right here and we make a request to update project mutation and we just have to pass the variables so what are the variables well the variables are going to be equal to the ID which is the project ID as well as the input which contains the entire updated form that's it so we pass the update project mutation as well as the variables just like so and we have to import the update project mutation from graphql and with that our edit is done it's quite similar to create but we had to make a check whether we are uploading a new image or not so now in here instead of the project form we can say await update project where we pass in the form the project question mark.id as well as the token and we also do router.push to the home page we of course need to import the update project from lib actions and we can say project ID as a string so we don't have any typescript errors now if we save this we should be able to test it out so let's try to change the image let's make it this great decorations application so we can say decorations decoration description and we can change this to decorations as well and we can change the category to front end let's click edit it is editing as you can see and if it succeeds we can see the updated Post in the home page isn't that great so with that said we can close all of the currently open files and let's go ahead and expand our application to admire it in its full Glory as you can see flexible it's already starting to look as it should it has the navigation bar we see the currently logged in account we have the footer and we have our posts we also have our complete create project model inside of which we can upload our images which are getting to cloudinary let's do this Finance landing page we can do that for the description we can add the URLs of finance.com here as well and we can select a category of backend and click create so this create project is done as well it should get added to the home and yep we can see it right here next.js sometimes doesn't automatically added we can see the project details of that project we can see the related projects by JavaScript Mastery we can click those links and we can even edit the project which doesn't seem to be working now and it looks like I cannot edit it because I just got signed out because the token expired which is good so this reminds me to Showcase that we have also implemented the authentication so I'm going to sign in real quick but yeah now if we go back we can indeed edit it we can exit the edit everything we developed so far is completely mobile responsive as well you can see it looks great and now we are on to our next step which is implementing the categories and the pagination but everything is going to be much simpler now because as you saw we keep reusing the great functionalities that we keep creating that is the ability to create scalable applications these cards are reused these are almost really similar to the ones we have on the home page the model is reused a couple of times so this is how we create applications and you don't even see it yet but we also took care of creating all of those environment variables to ensure that once we publish it it's going to work immediately on the deployed website as well with that said we can move to the next step which is implementing the categories and we can do that by going to the home page and then instead of just categories right here we can render a categories component so that's going to look like this categories and we can of course create that categories component categories.tsx rafce as always and now we can import it within the Page by double clicking control space and import and we can go in and we can start implementing the categories great job on coming this far in this video implementing categories is maybe going to be one of the most simple but most interesting things that we're gonna do today it is going to be a used client component but still we're going to use and leverage a lot of nextgs's built-in functionalities let me show you what I mean we're going to utilize use path name we're going to use the use router as well as the use search for Rams and that's going to come from next forward slash navigation now in the categories we have to of course get the categories so we can import the categories or the category filters from add forward slash constants that is just an arraylist of all of the categories that we have then we can Define all of the hooks we took above such as the const router is equal to use router const path name is equal to use path name and const search params is equal to use search params then we can create a div and within that div we can render a class name equal to flex between W Dash fool Gap Dash 5 and flex Dash wrap inside of there we're going to have a UL an unordered list that's going to have a class name equal to flex Gap Dash 2 and overflow Dash Auto finally we're gonna render dynamically category filters dot map where we're going to get each individual filter and then we're going to immediately return a button for each one of these a button is going to have a key equal to filter a type equal to button it's also going to have an on click equal to a function that's going to be called handle tags to which we're going to pass the filter so we can immediately Define that function cons handle tags is equal to a function that accepts a filter which is a string and finally we have to give it a class name where we can do it dynamically so if the category is triple equal to the filter meaning if it's the currently selected one in that case we can render the BG dash light Dash white Dash 300 and fond Dash medium else we can render the font Dash normal within a string of course and then finally outside of that we can give it PX4 for padding X py3 for padding vertical rounded Dash LG capitalize and white space no wrap and within it we can render a filter and for now we don't have access to this category what is that well that's the currently selected one so we need to know which one is currently selected and we can get it by saying const category is equal to search params dot get and then we can get the category field soon enough this is going to make a lot of sense so if we now save this you'll be able to see a list of all of these great looking categories and we can even scroll over through all of them with horizontal scroll or on your device you can just swipe through it if you have a touch device this is great so right now if we click them nothing is going to happen because our handle tax function is not yet doing anything but let me show you what it will do we can use the router functionality to push to the current path name so path name but then we're gonna embed the category equal to the filter and now if we save this all of this is client-side functionality right we're using State we're accessing the URL we're changing the URL but now if we click on front end it actually changes the category and believe it or not it actually should work or rather it will really soon this is it this is all that we had to do to implement the category picker but then on server side nexgs is automatically going to read the URL and based on the URL change we're going to filter out those posts so this is it for the categories component we can go back to the page and inside of here we can now read that data and pass the appropriate category to the fetch all projects to do that right here in the function we can get search params and we can destructure the category and of course we can set this to be equal to props and we can Define the props above by saying const props is equal to category is optional of a type string or it can also be of a type null so we can add it right here and this is going to be within the search params so we have to say const search params and then we can say type props is equal to search params is of a type search params which is also going to be a type and now we're good and I don't think we have to mention now because it is optional right here yep so now we have this category and we can pass this category over to fetch all projects right here as the first parameter we can go into the federal projects it is already accepting the category and we are already passing it to the project query and now if we click backend or click front end it's going to immediately work and all of this is working on the server side because we're just changing the search params and based on that it's refetching the proper queries and you can see how fast it is once you actually open them up it's incredibly fast because this is server side rendered great that's why I said that the categories component is cool because while it is client and while it is modifying everything the only thing it's really doing is changing the URL and then depending on the change of the URL the server side component fetches the projects that it needs to fetch great also we need to render the categories on the categories that don't have any posts yet so we can simply turn this into categories right here and now even on full stack we'll be able to go back and see where we have some of course the next part is to implement the pagination as well or the load more functionality so let's do that next of course first we have to create our load more component or I mean technically it's a pagination component but let's call it load more dot TSX and there we can run rafce and then we can of course import it right here within page at the bottom load more and we can self-close it now to that component we have to pass a couple of things that's going to be the start cursor which is going to be equal to data question mark dot project search and then question mark Dot Page info question mark dot start cursor this is going to be a link to the starting position that's how you do pagination in graphql now that I think about it we can extract all of these properties from this long URL so we don't have to repeat ourselves so we can do something like const cursors or pagination is equal to data question mark.projectsearch Dot page info and then we can simply say pagination dot start cursor we can move down and say end cursor as well and finally we can do previous page right here and then next page or rather it's going to be has next page and has previous page kind of like Boolean variables to let us know so let's dive into the load more and make use of all of these variables to do that we can say type props is equal to start cursor is a string and cursor is a string has previous page is a Boolean and has next page is a Boolean as well we can now get all these props right here by saying start cursor and cursor has previous page and has next page and that's going to be equal to props we'll also want to use the router here so this is going to be a use client component inside of which we can import our use router which is coming from next forward slash navigation and we're going to also use our custom button component coming from backslash button and here it's going to be used router not use route which we can then Define right here by saying cons router is equal to use router now how is the pagination going to work well first we're going to have a div inside of which we're going to wrap two buttons first we're going to check if we have access to a previous page then we want to render a button that's going to have a title equal to first page and a handle click which is going to call the handle navigation function and pass in the parameter all first and then we can duplicate that below and say if has next page then we can call this and say next and then we can say next right here of course we are yet to define the const handle navigation which is going to accept a direction which is going to be a string just like so so now if we save this we should already see those buttons if we have any so let's reload the page and we cannot seem to see anything yet because we are on the home page and we don't have any additional posts so what we can do is when we fetch the posts we then fetch all projects and within the projects query we can set the limit to first one that way we're going to have one post per page and we should be able to see a next button great now let's style this div for our button submit by giving it a class name equal to W Dash full Flex Dash Center gap-5 and margin top of 10. that should give it some space finally let's implement the functionality for navigation I was having some trouble implementing the functionality to go to the previous page so I implemented the first one and then we have the next Pages as well so in here we need to get the access to the current parameters where are we right now of course there is nothing there right here but later on once we go to the next page there will be something so we have to say const current params is equal to new URL search params and then we pass in the window dot location dot search then if direction is next and if has next page we want to add an additional parameter so we want to say current params dot delete start cursor like this with a lowercase C and we want to add the current params dot set and cursor to be equal to end cursor like this and now we can do another one by saying else if type or direction is triple equal to First and we have a previous page so has previous page in that case we can do similar so we can do current params dot delete and cursor current params.set start cursor equal to start cursor when we reference values it's going to be Capital C and right here it's going to be lowercase C for cursor when they're within a string great now once we do the navigation we need to get the new params by saying const new search params is equal to current params dot to string and then we have to form the path Name by saying const New Path name is equal to a template string of window dot location dot path name question mark and then we pass the new search perhaps and then we navigate to it by saying router.push New Path name so now if we save this let me show you how this works I'm going to click next and you can see that the end cursor was added this means that we should have been on the next page but so far we cannot see that it properly paginated so let's click next again and you can see nothing happens so let's try to reload the page on the second cursor and again unfortunately we don't see any new posts let's try one more time I click next the cursor gets added but we don't get redirected it is possible that nextgs is not dynamically rendering the new content I've had some issues with that before so going back to the page we might want to set up some directives for nextgs to know how to handle this stuff so we can say export const Dynamic is equal to force Dynamic this is going to force that the content gets refreshed when something changes and we can also export const dynamic perhaps is equal to true as well as export const revalidate is equal to zero these are some of the things that you can read more about in the next docs but sometimes I found these values to actually fix some of the problems of reloading the new content in this case that didn't really do it it doesn't immediately appear in the home page well these things fix that unfortunately the issue with pagination is something else and I think I know what it is we are changing the params but we are not reading them right here we're just reading the category so let's get the end cursor through params let's also add it right here next to the category and cursor is a string and now we can pass it as a second prop to fetch all projects right here and cursor now if we save this and go back to the home page and then click next still nothing happens so let's see if fetch all projects is accepting the N cursor and it looks like it is so it should make a new request to get another one project by the end cursor variable let's see if we're passing it properly it could be that the query is accepting a a uppercase C for the cursor so that might be worth a shot let's see if we switch it right here and cursor and end cursor that might do the trick so now if I save it and go back and click next there we go so we go to the next page but in this case it doesn't load the first one for some reason it thinks that it isn't there even though we do indeed have one page so I think when we have more posts this is usually working let me show it to you how it works on the deployed application so right here we have many posts the first eight visible on the home page and then if I click next it shows the next post and then you can even go further to check out the next ones and you can go back so all of this works flawlessly I'm guessing something with one post is making it not properly recognized that we can go back so I'm just gonna bring this back to eight once again and that way all of them should fit on one screen at this point in time but later on once you create more the pagination will appear now we can go back we can reload the page we can see both posts and this is great so the pagination is now fully working the categories are working as well that's great to see and in the meantime I got locked out so let me log in again and one of the last things that hasn't been implemented is the profile page so if you click profile right here or if you go to a specific user's profile you'll be able to see that it's a 404 right now we want to show something that looks like this you have JavaScript Mastery I'm a software engineer you have your recent work and then you have more recent work so it's a pretty simple page but let's do it together right now to do it we can go with an app create a new folder within the app folder called profile and then within it a new square brackets ID folder and finally a page.tsx and run refce if we do that and reload immediately you should be able to see a page appear right there there we go it just says page now we can start implementing it by renaming this to user profile we can import a couple of things such as import get user projects from add lib forward slash actions or rather add forward slash lib for slash actions and we can also set up the necessary props by saying type props is equal to params where the ID is going to be a string and this is coming right here if we destructure the params and then set that equal to props so how are we going to get the related projects for a user well we can see const result is equal to a weight we have to turn this into an async and then get user project and pass the params.id we can also pass a limit this limit can be higher because we want to show all users posts so we can do a hundred and we can say that this is going to return the result as user which is of a type user profile and this is coming from the common types and believe it or not we have already implemented the get user project action when we were doing the similar project so this is great then we need to check if there is no result question mark dot user in that case we want to Simply return a P tag that's going to say failed to fetch user info and we can also give it a class name equal to no result text but if we do have our user then we can return a new component that we're going to create called profile page and to it we want to pass a user prop equal to result question mark dot user just like so and of course our profile page doesn't yet exist so let's create it by going to components and then create a new profile page dot TSX and run rafce if we do that and then import it properly we should be able to see just profile page right here and here this should be a result so I misspelled that but now it should be good and there we go we can see the profile page and as I showed you before the profile page is going to be pretty simple it's just going to be mostly the layout so in the GitHub just down below you can find the updated profile page component and you can simply paste it over here it's mostly going to be utilizing the components we already have as well as just some regular layout so at the end you should have something that looks like this of course feel free to modify this within your code JavaScript Mastery software engineer whatever feel free to point these buttons to go somewhere and then you have your recent work right here so you can even use this kind of as your own portfolio and of course we can fully navigate from here to maybe a category from category to another category another post and then back to the user so all of this is working perfectly and of course this is also completely mobile responsive so you can see all your work right here this is great if I'm not mistaken we have implemented all of the functionalities of our flexible application which means that we are ready to deploy it that's going to be a bit tougher because we have a lot of environments that depend on our application console.cloud.google.com for auth we have to push the code to verse cell as well and update many environment variables but we're going to do it all together and I'm going to show you how to move from development to deployment so let's close all of the currently open files put the editor and the browser side by side and let's get started with deployment first we can go to verscell.com and click Start deploying then you can continue with GitHub and you can choose your project in this case we're doing the project next.js13 hopefully you deployed your own using GitHub before as well but before we deploy it we are yet to push the changes right we have 29 pending changes so press Ctrl C and then y clear the terminal and then run get add dot get commit Dash m second commit and then git push this is going to push all the changes and they might even be reflected right here immediately this is a project that was created five hours ago so this is okay I'm gonna switch to my organization account and click import you can choose your project name and then here you can put your environment variables so click there and then go to your envs copy all of them and then simply paste them right here into the first field it's going to automatically populate them we'll have to change a couple of them later on but that's okay for now let's simply click deploy this process is going to take about a minute so let's let it run and I'll see you once it's done and there we go our project is now live so let's click visit and as you can see everything is looking good but as I told you we're gonna have some issues with the sign in Google cloud and more so let's fix those little obstacles and get ready to deploy go to console.cloud.google.com apis and services and credentials go to the last credentials you have created and then you'll have to copy the URL of your newly deployed website paste it here in the URI without the forward slash and add the authorized redirect URI as well and add the API auth callback Google at the end and click save this should fix the authentication part of the application now we have to ensure that all other environment variables are good we can do that by going to project settings and then environment variables here we can see all of the environment variables that we have the next public graph based URL looks good this is looking good as well Google client ID and secret are good the next odd secret can remain as it is but the next auth URL has to be changed so we can go to edit and we can edit it to our current URL and click save the cloudinary variables are okay as well I think this is more or less it we changed everything we needed to change so let's go to flexible let's reload our application just to be sure or no as a matter of fact there's something you must not forget never when you update environment variables you need to go to deployments and then you need to redeploy by clicking these three dots and clicking redeploy and then again redeploy this process is going to take about 30 to 40 seconds so let's wait a bit and let's visit our application there we go let's click visit or no now we are in the new deployment you can just go back visit your project not this specific deployment and then just go to project and then visit this is going to lead you to the right URL let's sign in and it looks like we have access denied so let's see what this is about if we go to console or the network we should be able to see some more information about this so let's try to sign in once again unfortunately no information here which means that we must have gotten some on the server side this is a pro tip if you want to see the server side when the application is deployed go to nexjs and then visit logs inside of the logs you can see the new logs so you can click live and then we can try that one more time to see the latest locks we can see a 403 API auth error and unfortunately it doesn't give us more information it just says there's a warning and this is it so let's see what has been happening let's see if we have properly set up the credentials so this is going to be project next.js13 flexible for sellbot app so if we go back right here project next year is 13 flexibleversel.app and then the same one that has the API auth callback Google and then I think we did save it yeah so this should be reflected within our new application and we should be able to sign in but unfortunately we get errors let's ensure that our secret and all the other environment variables are properly set up so if you go to environment variables the most important ones are next auth URL which should be the link to our current project which it is we might need to remove the slash sometimes it poses some issues but hopefully not this time Google client ID and secret can remain the same and the next odd secret can also remain the same I think I know one thing that could affect this we have to go to graph base to fix it once you're in the landing page go to dashboard visit the new project I think it is this one right here go to settings and then environment variables we also have to add a variable here remember this one that we had within graph base e and V so that's going to be next auth secret and then we can pass in the value and we can click create I'm not sure if this is going to automatically push it we can give it a shot to test it out and it doesn't work so just to be sure I'm gonna make a push to the repo so then graph base updates it as well for example in here I noticed that we have some typescript error so what we can do is we can add a TS ignore just above that line right here and we can do git add git commit Dash m we can do dot dot dot and we can do get push so let's go back to next.js close all of these this is going to be updated as well I hope and then we can wait for the new deployment to go through and even though I don't see a new deployment here it must have gotten through on the graph based side so let's click visit let's close all of the other pages and hope for the best let's click sign in and we are in the last thing to test is whether the post creation works we can choose this nice landing page for task application so we can say task management task management landing page and that can be https Colin forward slash forward slash jspassity.pro GitHub URL the same and let's do front end and click create and if we open up the inspect element we can see that we have one error unfortunately not a lot more information maybe we can try to recreate it to see if it's going to give us some more info in the network tab so let's go with justjs Mastery Pro for all the fields to make it quick and choose front end clean the console and everything and click create and we get a 404 on the token side now it tries to get the undefined route right here so let's see how we're trying to make this get request because obviously something is undefined here most likely environment variables so if we go back and try to search for our token where we're trying to access it we have a get token request right here and this is the get request on the route but I'm wondering where are we trying to make a request to this route so we can search for forward slash API or just API forward slash and then auth and then we have the token right here I'm guessing yep and you can see that this is calling a server URL in This Server URL should be the next public server URL or it's a local host one so if we go back to our cell go to settings and environment variables we should be able to find a next public server URL let's see if it's there nope we just have a next auth URL next odd secret but definitely no next public server URL and we need this so let's add a new variable right here next public server URL and its value is going to be just the URL of our application and we can save it and then redeploy the application as I told you with this bigger applications you're going to have many dependencies from different services and you'll really have to ensure that all the environment variables are there so we can now redeploy the project to actually make it work so let's wait another 30 seconds and hopefully then we will no longer have undefined right here rather it's going to get the token properly and create the project so in the meantime while I'm waiting for deployment I'm gonna fill out all of these fields so this is going to be an nft project nft project description and we can leave the links as they are and we'll have to reload unfortunately because it says creating so let's go with another one just paste all the urls and let's see if it is deployed it seems that the build went through so I'm gonna click create we're going to open up the inspect element and we might have done it too soon we should have reloaded the application first so I'm gonna do a Reload and then click share my work we're going to go through the same process one final time this time with this medical dashboard and we can open up the console and the network just to see if everything's going to go well this time and click create we have a 200 for the token now the upload is successful as well as the graphql route now there is one thing that I noticed unfortunately with deployed version of the application I couldn't get it to immediately show the project after creation it's just one of these new next gs13 gotchas with server-side rendering where it cannot get it until you reload so if any of you knows how to fix it I would be helpful for that feel free to let me know in the comments down below but until then we'll have to reload to get the next post with that said the post details is working the post creation is working as well and let's look at the profile page there we go this is working perfectly of course it is all fully mobile responsive and we have successfully built our flexible dribble.clone application for developers I want to say huge thanks to graph base not only for sponsoring this video but for creating such a phenomenal tool that allows us to really quickly spin Up full apis and applications so we can use the power of graphql with graph base to build full stack applications so great work guys and I'm loving the new landing page on top of that if you came to the end of this video that means that you are ready for the master class in the master class we build more Nexus 13 applications with Mentor assistance complete PR reviews and a three month long crazy Capstone project that you can use as a foot through the door into the industry or even to get a mid or or senior level job so if this is something that sounds interesting definitely check it out by going to jsmastery.pro for slash masterclass with that said huge thanks for coming to the end of this video I'll see you in the next one and have a wonderful day [Music] thank you
Info
Channel: JavaScript Mastery
Views: 61,433
Rating: undefined out of 5
Keywords: javascript, javascript mastery, js mastery, master javascript, next js, Next 13, Next.js 13 features, Next.js 13 tutorial, Next.js 13 folder structure, Next.js 13 client components, Next.js 13 server components, Next.js 13 routing, Next.js 13 dynamic routes, Next.js 13 nested routes, Next.js 13 serverless, Next.js 13 route handlers, Next.js 13 full-stack apps, Next.js 13 data fetching, Next.js 13 SSR, Next.js 13 SSG, Next.js 13 ISR, Next.js 13 application, Next.js 13 course
Id: 986hztrfaSQ
Channel Id: undefined
Length: 281min 33sec (16893 seconds)
Published: Sat Jun 24 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.