Create a SaaS Application with Next.js.14, Stripe, Kinde, Prisma, Supabase and Tailwind

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
did you ever go to Twitter and then see those Indie hackers posting their Mr screenshots like $5,000 here $10,000 there $20,000 here and you thought to yourself like damn what the hell am I doing wrong well this will actually change today because I will take you from A to Z on the technical side we'll actually look at everything and then create a full scale SAS application we will start off with creating a beautiful marketing site we'll then go over and actually build a off integration using kind today's video sponsor then we will actually build our dashboard where the user can change the name change the color theme change the building settings subscribe to our plan using stripe and a monthly reoccurring subscription we can then create notes delete notes view notes edit notes whatever you want to do so I will take you from A to Z and then you will actually build your first fully functioning SAS application but hey don't take my word for it let's let's go and check out the demo which I have right now on my screen and which we'll build in today's video so on my screen you right now see what we'll build today so this is the current marketing site which looks very nice in my opinion then we have right here the theme switcher I can switch from light theme to Dark theme and if I refresh the page the theme of course will be kept persistent because of local storage then I can click right here on sign in and then we'll get redirected to kind which is our today's sponsor to make authentication easy I will now sign in with my Google account you now see I'm logged in and you now see also that I have right here now my user navigation where I can log out if I want to I can write you now create a new note so let me create a new note let's just say hey how are you and then let's just write some gibberish for our description I will now click save now you will see now we have a pending State also our cash is revalidated and we'll be redirected to/ dashboard I can now again edit this note if I want to so I can say hey how are you uh today and then I can click on Save now again we have a pending State and we'll get again redirected now you see we have an update right here so I can now again delete this note if I want to we have an pending State and then you again have this default State I can now for example click on the settings page right here I can change general information for my name but I can also change the color scheme for example let's change it to Green I will click on Save now we will now have a revalidation of the cache and you see we now have a new color scheme I can also click on billing right now and now I can open my customer portal if I don't have an active subscription I can subscribe but since I'm already subscribed I can now open my customer portal so let me do that you now see I got redirected to the swipe customer portal and this also fully works if I click to go back you see we get redirected back to our dashboard now let me show you how our bilding actually looks like if I don't have an active subscription now you see see if I don't have an actual subscription I can right here click to create a new subscription and then I will get redirected to stripe checkout to check out let me check out real quick so you see we got redirected and now we have a successful payment statement right here so great you see that's our demo and that's what we'll build today but now since you know how our application will look like let's also talk about what we'll use to build ours so we'll of course use as in framework NEX shs 14 with the app router so server components we will use for styling chatsi and UI which are accessible and style components with TN CSS for authentication we will use kind of which is a very nice authentication provider and also nicely the sponsor of today's video and then we will of course also use Prisma and superbase which provides a postest database to make our whole database layer work at the end we'll also use stripe of course to make subscriptions work and that should be all for today but now I hope you enjoy today's video so now let's go so to get started I will CD into my desktop directory and CD into my YouTube directory and then inside of here I will want npx create D next- apppp at latest to install the latest package of next shares now the CLI will ask me a few names so we'll name our application I don't know Marshall Das SAS I think that's good then of course we will use typescript we will use isint then of course we will use TN CSS we won't use the source directory because we will use the app router and we won't customize the default import Alias the CLI will now install next shares this will take about a minute or two and once that's done I will come back so the CLI has now finally installed next shares that means I can now head over to visual studio code and open the project as you now see I already opened the project and if you want to do the same you can go on top on file and click open folder but now we have right here the default temp template and now what does the default template actually ship So currently we have right here in the page. TSX the index page and this is the default index page to see it we can open the terminal with either command J or on top terminal and new terminal inside of here I will now start the def server so with npm1 def you will now see the def server will open on loc Clos 3000 so let me head over to loose 3000 so I'm now on Locos 3000 and what do you see well you see the default template which I just told you about so to see it again right here we have the page. TSX which is the index page and that's the code and that's what you now see on our def server what I want to do right now is actually delete everything right here in the index page so everything inside of this return statement and what we can now do is instead of that let's just render a H1 and then let's just say I don't know um hello from the index page just to see if everything works and yes you see hello from the index page now there's one problem right now and that's that you see currently we have a black background now this shouldn't be it actually should be a white background color now how do you change it well if you head over to the global. CSS file you will again see a bit of default Styles which ship when you create a new nexs project so what I will delete right here is everything right here I will just not delete the at T classes we need the add TN classes to make TN CSS work so now I've have deleted everything besides the ad tent classes and if I now head over you now see we have a white background color which is very nice and now what's the first thing I want to do well the first thing I want to do is actually create a Navar and to create a Navar what I will do right now is head over to ui. shen.com and what Shian UI if you ask me well Shian UI is a styled component component Library which Builds on radex UI what's radex UI well redex UI is a non- styled accessible component library and shats and UI Builds on RX UI takes those non- styled but accessible components and just Styles them in a beautiful way so that's why we will use Shaden UI in this project so to get started I will click on docs installation and for the framework we will use snack shares because that's the framework which we use right here we have a quick start guide we already did step one which is to install a new NEX project the second step is to run the shats and u i CLI so I will just copy the command right here and I will use npm since we use npm for the project then let me open the terminal let me stop my def server I will clear everything paste the command again and now the CLI will ask me again a few questions so for the style we will use default we will use as base color slate and CSS varibles sure let's use them and now right here the C now installs everything and now everything is set up so what we can do now is actually install a few components so to get started let's first of all install a button component and right here you already see a preview of how the component will look like right here we have the installation so let's copy npm go in our terminal install that let me also install a drop down menu since we'll need that for our theme toggle so let me click on npm and Al install that what you will now see is actually if I open my Explorer right here the um CLI has right here created a new components folder with an UI folder nested inside of it now inside of this UI folder you will see that all of the shats and UI components are actually um created or generated or they live in this folder in that case and right here you also see all the Styles and if you want to you of course can change them to your liking but we won't change anything because they already look beautiful as they are so now we have installed the button and the drop- down menu so what we now can do is actually create Dark theme or a dark theme Toggler for that you can right here click on dark mode they have a guide on how to create dark mode in next shares so let me click on next shares and the first thing we need is next themes what's next themes well that's actually the package which makes the whole process very easy it helps us with storing our session or not our session but our theme preference in a local storage and so the user can just um I guess change the um theme preference and it will still kep persisted even though uh even when the website is reloaded so let me copy right here the installation command let's open our terminal let's install that then the second step is to create right here a theme provider so let me copy the name right here theme provider let's go in the app folder let's create a new folder which will be called components and then inside of here let me paste the name theme provider. TSX now for the file I will just copy the content right here I don't need to change anything everything's already perfect as it is then the next step is to wrap our root layout with the theme provider now why do we have to do that that's because we have to pass actually the theme preference to all of our children and that's why we have to WRA our children with a theme provider so what we have to do right here is let me copy the theme provider right here let's go to our root. TSX or not our root but our layout. TSX X and then right here we have our children so what we have to do now is actually wrap our children with this theme provider as you see right here now there's one important thing actually let me first of all close right here also the theme provider so let me copy it let me paste it so now again there's one important thing um the theme provider if you write you double click on it it will tell you to import it from next themes now it's important that you don't import that from next themes because you'll get errors what I want you to do is import from our components since this is again a um component which uses state state has to be hydrated on the client and that's why also we have to mark our theme provider as a used client component because again it has to hydrate so now I have imported our theme Provider from our components and now everything should work now the next step is actually to add a mode toggle and with the mode toggle you can just change the theme preference as you see right here so let me click on code right here and now you see see how this code is written so what we'll do is open our Explorer go in the app folder components and let's create a new file called theme um toggle. TSX now right here let's uh just copy the code so let me copy it and paste it inside of here and do we get any errors no we don't get any errors so that looks good now one thing I will do right here is change the name let's name It theme toggle and not mode toggle and now we have actually created a theme toggle so to see it right now let me open my terminal let's clear everything let's start our def server with npm1 def this will again open on loc 3000 so let's copy that and open it right here in a new browser tab so now right here you see we don't have any theme toggle why is that well that's currently because our theme toggle is just a component and it isn't rendered anywhere so what we'll do right now is go into inside of the page. TSX and then let me delete this return statement let's div and let me render our theme um toggle and this is imported from our components if I now um save that actually go back you now see right here theme toggle so if I click on it and click on light mode you now see the theme preference changes to whatever we want and if I reload the page you see the theme preference is still kep persistent so this is very nice so with this now sorted out we can actually create now the naar so let's do that to do that we will go in our Explorer in the app folder components folder and let's create a new file called navb bar. TSX now how do we always start in this file well we have to export a function so let's do export function let's say nav bar and then let me open this function inside of here let me create a return statement and then in the return statement let's use a nav element so right here let me actually start with styling the nav bar let's give it in class name let's do right here border of bottom let's do a BG of background so the background color of the um CSS variables which we installed with shatan UI then for the height I will use a custom value of 10 viewport height so 10% of the total height then let's give it the flex and items of Center then inside of here I will create another diff element let me give it a class name of container Flex items which will be Center and justify which will be between now inside of this diff element what I will now do is actually create a link and I will use the link component right here imported from next /link now why do you use the link component and not just the normal aack as you know it well the link component has actually a few benefits so first of all client side rendering prefetching and just in total it's um a nice experience for the user we don't have any hard refresh but we have a client side navigation so now right here the link component currently um complains a bit and that's because we have to give it an HW and the HW will just be the Slash for our index page now in the link component let's render a H1 tag and let's just say Marshall SAS I think that's fine um let's save it let's see how that looks and if I now go back you see nothing why is that that's again because we have currently a component which does not render anywhere so what I will do right now is actually go in the layout so right here in the layout in our root layout and then just render our nav bar above our children so let me import our Navar right here for from our components and if I now save that and go back we should see a Napa right now and that's what you now see on the top we have right here Marshall sass with a little border on the bottom now the problem currently is that the title or our logo in that sense is not big enough you barely see it so what I will do right now is go back to our nafb component give it a class name and it will be font of Bol and text of fre XL let's see how that looks and yes that's already way better because it's now way more bold so now what's the next step well I think the next step is actually um on the right side so on this side right here on the right I now want to get our theme toggle and I want to have our lockin and sign up buttons so what I will now do is go under this link um element or component and create a new diff element let's give it a class name of flex items which will be Center and then also a gap of X5 so in between of all uh items I I want to have a gap X or I guess padding on the X AIS of five now inside of here what I want to do is render our theme toggle so let me get our theme toggle and let's see how that looks actually yeah you now see on the right side this theme toggle which looks quite nice so now what else do I want on the right side well I want to have a lockin button and a sign up button so what we'll do right now is under the theme toggle button right here let me create a new diff element let's give it a class name of flex items which will be Center and a gap X of five now inside of this diff element I will create two buttons for that we'll use the button components from shat CN UI the first button will just say sign in and then the second button again we'll use the button component will say sign up now if I save that and go back you will actually see that both buttons currently look the same I don't want that I want the sign up button to have a bit of a different style to the sign in button so what we can do is actually right here for the sign up button give it a variant and for the variant I will say secondary if I now save that and go back you now see that the buttons currently look different and now I just think this has now a better UI and uh ux for the user so now you see our project has about four buttons I guess so the first one is our logo and if I hover over our logo you see on the bottom left corner that it links to our index page so low close 3000 on the right side now we have right here our theme toggle if I click on dark mode right here you see our background color changes if I click on light it again changes if I now again click on dark mode and refresh our page you see the preference is kept persistent and we don't see any flash so this is very nice but now we have a problem if I click on either sign in or sign up you see nothing happens this is of course not what we want to do we of course want this buttons to work so let's actually change that how do we change it well what I want you to do right now now is go in my YouTube description and click on the first link so let me click on this link right now and let's head over to this website so now if you clicked in the YouTube description on the first link you should now be at the same website as I am well what is that website well that's actually kind our authentication provider for this video and kind is actually friendly enough to sponsor today's video to make authentication for us very very easy now what exactly is kind well again kind is an Authentication provider which makes off very easy you have multiple choices of what you can actually Implement you can make all off work that's what we'll do so GitHub and Google you can also make password list off work so with magic links that's also what we'll do right here but if you would now want to extend that actually to SSO or multiactor off credentials off or machine to machine connections it will also be very very easy thanks to the Simplicity of kind authentication but now the cool thing is they don't don't only offer off I mean that's a bit boring right the nice thing is they actually also offer user management and with that also authorization this is very cool because it's actually not that easy to build it on your own and it's very great that kind actually offers it inh housee and the nice thing with kind authentication is actually that they are quite affordable and also way cheaper than for example off zero also we get in total 10,500 free users and actually not free users but active free users which is again very nice so that's why we will use kind in this video and thank you kind for sponsoring today's video so now to get started you will either click on sign in or start for free if you don't have an account click on start for free I have an account so I will click right here on sign in this will now redirect us to the login page right here so let me click on GitHub since this is actually what I chose to create my account so as you see I have now been redirected to the dashboard of kind and I'm currently already in a project or business as they call it but we of course don't want to do that so what I can do right here is on the top click on businesses and click on switch business now right here we will actually come to the dashboard where you see all of our projects So currently I've already two projects let me click right here on ADD business or in other terms add new project let's give it a name so I will name it Marshall SAS now for the domain I will WR here also add nextjs because I already have a domain which is called Marshall SAS and then for the region I will actually choose it to USA now right here why do I choose as a region the USA well it's actually quite simple later on when we deploy our application to Vell I will actually also deploy to the US or our function region will be in the US and it's also always quite beneficial that the region of data where it's stored is the same as where your application is stored so that's why I will choose the USA and now I can click on save or in that case uh I will now create a new project so let's wait for that so now you see the project has been created so let me click on it right here so on the link this will now redirect us to the dashboard of the um actual project and once we are inside of here let's actually do this quick start guide so I want to start a project from scratch or use kite in my existing project so since we already have an existing code base we have created a new next shs project I will click on the second op uh option right here now let's click on next so for the next step then for our Tech we use next shares so let me click on that and let's click on next and then how do we want our users to sign in well let's use email let's use Google right here and let's maybe also use GitHub so now we use passwordless off so magic links Google o off and GitHub o off let me now click on next to actually see the next step and now there actually no further steps and now we can actually get started right here I will click on no thanks I will explore at my own pace so now we are in the dashboard as you see and the first thing you see is we don't have any users but we'll change that trust me um what I want to do right now is Click right here on the doc so on the right corner let me click on open link a new tab and now we are in the docs let me search for next shares right here we have the next shars um docs so let's click on them and on the left side by right here you see the docs for the individual SD case and since we use the app router let me use the next sh as app SDK version 2 so now right here we have our quick start guide and the first thing we have to do is actually install right here the next shares M SDK so let me click right here on this installation command let's open our terminal let me stop the def server and let me paste the installation command now you see we have successfully installed the kind um nexs SDK so let's continue and see what the next steps are so the next step is to set callback URL so let's see we have to go to the settings so let's go go back right here let's click on settings then the next step is to click on applications so let's see where do we have applications let's see right here applications then what's the next step our app and view details so let's click on view details and then the next step is to add callbacks URLs so let's see we have right here two callback URLs and they are already actually configured so we don't have to change anything they currently look very nice now what's the next step the next step is to configure our environment varable right here so we have to add Our Kind client ID client secret ISS URL site URL and then where we want to redirect after lock in or lock out so right here let me just copy all of these environment variables and what I will do now is open our Explorer close everything and then in our root directory let's create a EnV and then in this EnV let me just paste everything I just copied now before I continue let me right now go to ourg ignore file and add in V right here now why did I add this do EnV right here well that's because I don't want to push my secrets to GitHub and I want to make them private so now let's go back to our inv file and now you see again our environment variables so what do we have to do right here well we have to add Our Kind client ID kind client secret and kind issue URL for that let me go back to our dashboard and right here again in our details we already have everything so first of all let me copy the client ID and let me paste it right here for our client ID then the next step is let me copy right here our client secret and let me paste it right here for the kind client secret and then the last step is to add Our Kind issuer URL and that's right here our domain so let me copy the domain and let me also paste it right here so now we have created the client ID the client secret and the URL and now for these three environment variables we don't have to change anything because our site URL is actually correct with low close 3000 our post log out uh redirect URL is also correct since when we log out I want to redirect to our homepage and then our post login redirect Ur is also correct since after we log in I want to redirect to dashboard so now that's very nice and very cool and now we already finished with the environment variables and then the next step is to set up our kind of Route handlers for that we have to create an API folder an off folder and kind off folder and then the route. TS file so let me actually do that let me open the Explorer let's go in the app folder let's create an API folder then in the API folder I will create an off folder as you see right here API off then right here we'll use these brackets and kind off let me create a new folder in off with this name and then right here let's do route. TS now routts is actually used to make the r Handler work and if you name it somehow differently it won't work now for the content of this route Handler I will just copy everything from kind off since it's already configured and now actually our route Handler is done and you could also say that our process now actually works so let's see what the next step is right here we now have a migration guide we don't need it since we already on the newest version and now we have come to the last step and the last step is how to set up authentication and thankfully it's very very easy because all you have to do right here is get the login link and the register link and then you wrap whatever button you have so if you head over to our nav bar right here where is it let me open it you right here see we have a button or two buttons all we have to do is actually wrap this buttons with the lockin link and the register link and then we're actually done so let's actually test out if everything works so let me copy this import statement right here for the import uh register and uh login link so what I will now do is wrap our sign in link with this loog in link which I've just imported so let me wrap it right here here and then for the register or sign up link let me do the same let me get our register link and wrap it uh with our button let me save it let's go back to local 3000 um you see the def environment is not running so let's do an npm1 def to restart our def server this will now again take a bit so let me actually wait for that so now you see my def server is again running let me reload it just to be safe and now I think it's time to test it out so let me right here click on sign up we should now be redirected actually let's see it loads right here on the top as you see and we got redirected so now we are on this domain on the kind domain and you now see I can actually sign up so let me right here just choose GitHub actually so let me click on GitHub you see we now have a nice loading indicator and this should now redirect us if it's successful to the SL dashbot page and as you see right here on the top yourl we got redirected to/ dashboard which is quite cool now right here we get in four for not found why is that well that's because we haven't created an actual dashboard page so what I will do is open our Explorer then in the app folder let me create a new folder called dashboard and then in the dashboard folder let's create a page. TSX now how do we start right here let's do an export default function let's just call it um dashboard page I think that's fine and let me open that function inside of here let me just return a div and let's say H1 and let's say hello from the I guess dashboard let's save it let's go back let me reload it and as you see now we don't get any errors anymore and we now have right here hello from the dashboard so now this fully works but now we have a problem right even though we are in the dashboard and we are also signed in we still have to sign in and sign up buttons we of course don't want that when we are signed in we want to get the sign out button now to fix that it's actually quite simple let's head over back to the nav bar let me close everything right here and and just leave the Navar open and now the first thing to actually show the log out button we of course first have to be sure that the user signed in so that the user has an a valid session now how do you do that well thankfully kind makes it quite simple if you want to you can go again to the docs right here and if you scroll down a bit right here to kind of data you see that we only need one function actually and that's the kind server session so let me right import that so right here we import get kind server session from kind OSS kind of nexs SL server now in the Navar component what I can do right now is do a const then right here we can dest structure it I will leave it empty for now and this will be equal to get um kind server session now right here you will see is if I click right here on control space bar you'll get all of the options which you want to use in your project now I actually only need one function and that's the is authenticated function and with that I will then just see hey is the user authenticated or is the user not authenticated so right here we have our diff with our lockin link and our register link let me just copy this St for now and what I will now do is right here inary so right here we'll do an await is authenticated and if this is true let me return something and if this is false let me return something else so first of all if this is not true let me return again this loog in and register link button and if this is actually true so the users authenticated let me just right here uh use a button component and let's say lock out let me save that now you see we get an error right here with a it tells me a expressions are only allowed within async functions now the thing is actually since this is an server component it's actually safe to Market as a sync right here since this will not be leaked to the client since again it's in server component and only once on the server so now actually what we can do is head over to our next s page and we load it and now on the right side you see a lock out button now again why do we see the lock out button that's because we currently have an a valid session and that's why we can lock out if we want to um but now if I click on this button lock out you see nothing happens so how do you fix it it's again thankfully very simple so right here where we import our register link and login link we can actually also import a log out link so it's actually the same process as with the lockin link and register link you just have to wrap the element with which you want to lock out so right here we have our button and what I will do is wrap this button with our lck out link component and if I now save that and go back you see our page let me just reload it to be safe let me click on log out and what should now happen is that we should get uh redirected to our index page and as you see that's exactly what happened we got redirected and now in the Navar we see the sign in and sign up buttons so now I can again click on sign in right here we'll get again readed directed to the kind page right here I can log in with GitHub so let me click continue we see the loading indicator on the bottom and we now should be redirected to/ dasboard and that's exactly what you see we now have in the N but the lock out button and this works perfectly so now let me again click on lock out we should again get redirected and yes you see this works perfectly Now isn't it great we have made authentication work in just a matter of minutes we have created a signin button we have created a sign up button we have made GitHub o off Google o off passwordless off work in just a matter of minutes everything fully works we can sign in sign up log out create accounts um log in in our accounts again very very easily if you know head over actually to again the kind um dashboard click on home right here you will now see right here you have one active user now the active user is myself or for you it will be yourself but if you would now have multiple users uh you would actually see them all in your dashboard which is quite nice but now since we have made the Nava work and the authentication flow let's actually now create our um homepage So currently our homepage or marketing site in that case is completely empty and we just have this little um light bulb to change our theme I of course don't want to do that so let me change that for that let me go to our page. TSX now the page. TSX is our index page and as you see we currently just render the theme toggle again of course I don't want to leave it like that so let me delete everything in the return statement and let me actually return a section now in this section element I want to create a class name let's right here just do a flex items of Center justify of Center BG of background and let's also give it an height of a custom value of 90 viewport height now what's again this 90 viewport height well it just tells the screen hey I want to take 90% of the total height of the screen so so 90 viewport height now inside of the section let me create a diff element um let's give it a class name this will be relative then we will have items which will be Center W which will be full padding X of five and padding y of 12 MX which will be Auto LG of PX of 16 uh Max width which will be 7 XL and on medium devices so devices which have a minimum width of SE uh 768 pixels results that's right you do a padding X of 12 now inside of this diff element I will create another diff element I know you love to see it right here let's create a class name of Max with which will be fre XL MX of Auto and text which will be Center then inside of this div we'll create another div and this was now the last uh div for now now inside of here what I'll do now is create a span element let me give the span element a class name of W Auto let's do right here padding X of six padding y of three then a rounded which will be full and a BG of secondary then inside of the span I will create another span and then inside of here let me just say um sort your notes I don't know easily let me spell that correctly I think that's correct let's see let's see how that looks and right here you now see sort your notes easily which is quite nice let me actually delete the do uh the dot I don't need it let me also style it since it's currently does not look good so let's give it a class name of text which will be small font which will be medium and text which will be primary let's see how that looks and yes it looks quite nice now one thing you currently see is that we have in theme where our color is like an darkish blue or black I am not quite sure what we can do right now is head over to ui. shatan and actually change the theme so if you click right here on themes you can change the color or the base color of your theme now I will write here to use orange so let me click on copy code and let me just copy the whole code I can now go to our global. CSS file and actually change this add layer base where we actually use the CSS variables so let me add that and if I now go back to our next s page you now see that the primary color has changed to this orange color let's see how it looks in dark mode and yes you see it looks very very nice so now we have created a span element right here and now the next step is actually to create like a little title so what I will do right now is go back to the page. TSX and under the first span and under the second span I will now create an H1 tag and right here let me just say I don't know um create let me spell it correctly create notes um with ease I think that's fine let me also style that since if you check it out right now it does not look good at all so let me give the H1 a class name of margin top which will be eight text which which will be fre XL font which will be extra bold let's also do a tracking which will be tight and then I think also a LG of text which will be 6 XL let's see how that looks yeah it looks quite nice as you see it's now more bold and also we have some margin on the top now another thing I also want to add is a small description so under the H1 tag let me add a P tag and let me actually just add a bit of low ipsum and now if you check it out it does not look nice so let me style the pag right here let's give it a class name of Max with XL MX which will be Auto margin top which will be 8 text which will be base then let's also do a LG of text which will be XL and text which will be um secondary or foreground let's see how that looks and yes you see it looks already a bit better let me make it a bit uh less content I think it's a bit too much so let me delete that this should look better and yes it's now a bit uh better as you see now the last thing I want to do is on the bottom I want to have a sign up button so what I will do right here is go under the P tag and under the diff tag let me create another diff element let's give it a class name of flex let's do right here justify which will be Center and a Max with which will be SM a Max which will be Auto and margin top of 10 now inside of this diff element I will create a button component or I will use the button component from our components and inside of here let's say sign up um for free let's see how that looks and that's what you see right now you see it does not look good actually so what let me actually uh style our button let's give it right in size property and the size property will be LG and let's also give it a class name of w full let's see how that looks now this is uh how our button currently looks you see it does not look good so I have misspelled a few things so this should first of all be spelled correctly so justify Center and then Max width should not be XM but SM now let's see how that looks and yes this already looks thousand times better as you see so now you see our actual marketing site has been created now there's only one problem if I click on the sign up button you see nothing happens so to change that what you can do is go to the Navar let me again import this um components from kind I'll go back to our index page um uh paste our Imports and all I need is the register link component I can now wrap this button in our register link component and as you will now see if I save that and go back and click on the sign up for free button we should get redirected to the kind website let's see and as you see yes we get redirected and this button now also works so now since we have created the fun stuff so the nav bar the whole authentication process a beautiful marketing site I think we should now head over to our dashboard and create the actual software as a service so let's do that now the time has come to make our dashboard look nice and it will be actually quite simple how we'll create a NIC looking dashboard so if you check our Explorer right now we have our app folder and then inside of here we have our dashboard folder now currently in our dashboard folder we only have a page. TSX so the index page that you see right here but of course we don't want to leave it like that because at the end of the day our dashboard will have multiple pages like the index page then the page to create new noes then the page for the settings Etc so there's currently the problem or there will be a problem if we don't fix it that for every page that we will create we'll have to again create the same layout now a simple fix for that is actually to create a global layout file for our dashboard so what I'll do now is inside of the dashboard file let's create a layout. TSX and now this layout will be a applicable to all the files or all the pages in our dashboard uh subdirectory so now inside of here what I'll do is first of all Let's do an export default function let's name it dashboard layout and then let me just um open this function right here now inside of here let's create a return statement and for now let's just say um div and H1 hello from the dashboard layout let's save it let's see what we see right here and now we see hello from the dashboard layout but now if you watch closely you will see a problem right now we have this dashboard layout which is nice but what happened with this index page so with this right here hello from the dashboard I can't see it anywhere well it's actually because we don't render it right here currently this layout file now works like a index page but to fix it if you actually also check the uh root layout we have to pass our children if we pass our children it will render the actual pages so the index page then the settings page Etc so again what do we do right here we actually have to right here this structure our children in the params then our children let's give it in type the children will be have a type of react note react note is imported from react and then under the H1 I can just uh pass my children so let's check it out and now you see hello from the dashboard layout and then we render the children so we see the index page hello from the dashboard so we see how this works now let's actually create the layout because this is of course not how it will look like at the end so let me delete this whole diff element let me create a new diff element let's give it a class name of flex Flex of call space of y 6 and margin top of 10 then inside of here I will create another diff element let's go an class name this will be container let's give it in Grid and flex of one then we'll give it a gap which will be 12 uh medium of grid which will be calls of letum custom value which will be 200 pixels uncore 1fr now what exactly is this MD grid called 200 pixels uncore 1fr well it's actually uh quite simple so if you can remember on the left side we'll have our nav links and then on the right side we'll have the content and with this I say hey let's do uh right here the dashboard nav so the links 200 pixels and then the whole other space let's leave it for our layout or for our pages so we say hey nav bar let's do 200 pixels and for the rest just leave it 100% so that's uh what we do right here with this 200 pixels underscore 1fr now inside of this diff element let's create an aite and then let's give it also class name so let's do class name of hidden so if we're on a small device I don't want to show this um nav elements then let's give it in custom some width value of 200 pixels that's do Flex of call and on medium devices Flex then inside of here we'll render a component for now let's just say H1 of hello and then under the aside right here element let's do a main element and let's just wrap our children or render our children inside of this main element let's see how that looks right now so let's go back and now you see the layout on the left side we have um right here where later on our links will live and then on the right side we have the area where all of our Pages or in that case our content will live so now I think the time has come to actually create the nav items and for that again we'll create a separate component so what I want you to do now is open your Explorer again let's go in the app folder components folder and let's create a new file called dashboard nav um. TSX now how do we start inside of here it's always the same we start with an export function let's name it um dashboard nav let me open that and then inside of here let's return a H1 with hello what we can do now is actually instead of right here rendering the H1 let's render our new component which we have created which is called dashboard nvf so I imported from our components let's save it and as you see still everything works as it worked before great so let me now actually style our dashboard nav and actually make it work so let me delete the old return statement let's create a new return statement let's use the nav element right here and let's first of all give it a class name of grid items which will be start and let's do gap of two actually now inside of here I will actually now render our items now you could of course just render item by item do it hardcoded it works I guess it's fine but we won't do it like that we will actually create an um array and then map over the array and then just render the items so above our function right here what I want you to do now is let's you an export const nav items this will be equal to an array with multiple objects now for the first object let's give it a name the name will be home for our homepage and then also we of course need an H so where this link will um actually navigate to and the H will just be slash dashboard since this will be the index page let's also give it an icon and for the icon uh let me actually first of all add an comma uh for the icon we'll just do an home icon imported from Lucid react let's create another object or in that case another link so right here let's give it a name for the name let's just say settings for the h this will be um/ dashboard slash settings and then let's give it an icon and for the icon this will be settings not in strings let's write it again settings imported from Lucid react then let's create another object or a link let same name this will be building let's give it with an HW the H will be slash dashboard the um slash billing and let's also give it an icon and for the icon this will be credit card again imported from Lucid react so now this looks nice we have now created n away with in total three objects or three links and now we can uh map over them and actually show them so how do you do that well inside of this nav element let's do uh get our nav items which we have created right here let's do do map let me get the item and let's also get an index and let's just return that inside of here now inside of here I can actually render a link element or a link component imported from next link let's self close that let's save that and right here you see we get an error we actually get two errors first of all missing key prop and property H is missing so first of all let's give it in key prop for the key prop it will just be the index and for the hre this will be the item. hre now in inside of this link element we can now actually render our item so what I'll do is create a span element now inside of the span element let's first of all render actually the link name and the icon so right here first of all let's get our item do icon this is in self closing tag let's create a class name of margin Y 2 age of four and also width of four under that let's uh render a span element and with our item. name let's see how that looks so let's go back let's see um now you see right here our logo and also the nav item now you see they are not styled also they are not um aligned horizontally they're currently aligned vertically and this of course does not look good but we'll fix that right now so right here for the span element which is actually the um parent element we'll actually style this span element so let's go in class name and now instead of writing it in strings we'll right here use these brackets get our CN so that's actually in helper which I can import from our lip file or our lip folder and then inside of here let's actually write a few Styles so first of all group let's give it in Flex item switch will be Center and if you save that you already see this looks now already way better but still we are not done um let's give it an rounded which will be medium padding X of three padding y of two text which will be SM font which will be medium let's now see how that looks yes this is already way better you see it's now a bit more spaced out and also the text looks a bit better now also let's give it in Hover the hover will be BG of accent let's see how that looks yeah this already looks very nice in my opinion and now uh another thing is currently also the text let me also uh change our text color on Hover so let's do in Hover of text which will be accent foreground let's see how that looks and yes this looks beautiful in my opinion let's see how it looks in uh light mode and yes this also looks very very nice but now there's one problem currently we are on the SL dashboard route so the index page of the dashboard and in that case also our homepage right here or this home nav link should have this uh background color so how do we actually achieve this well let me show it to you so the first thing we actually have to do is get the path name so our path name for example currently is/ dashboard if we'll click on settings it will be slash dashboard slash settings so what we have to do right here is first of all get an helper function so let's do const path name this will be equal to use path name now use path name is imported from next SL navigation and if I now save that you'll see we'll get an error and that's because use path name only works in client components so what we have to do is on top right here just Mark our component as use client if I now save it and go back you'll see the error is now gone and still everything works what we can do now is actually console lock our path name so let's do console.log path name just to see what it splits out so if I now save it and go back let me reload the page real quick you will now see in the console we now uh console loog SL dashboard so this is our current path name and what we want to do now is actually right here in our front end code check if the current path name is equal to the item. H and if it's equal I want to show a background color and if not let's leave it transparent so how do we do that well right here let me add in comma and then let's get our path name right here and now we will check if this is equal to our item. HW what I want to do is so I will use anary if this is true let's do in BG of accent and if this is not true let's use some colon and let's say BG of transparent let's save it let's see how that looks and now you should see yes the homepage or this home nav link now has this beautiful background color and if we would now for example click on this button if it would work currently it does not work then the settings page would have the corresponding background color let's see how it looks in dark mode right now and yes it looks very very nice so now I would actually already say that our dashboard NV is fully working we show all the links and they are also styled very very nice maybe one thing that you could do if you want to do that it isn't a must for our item do uh icon right here we can also add an text which will be Prim AR again if you want to then you will see that our color has now changed to this nice um orange color so our primary color of shatan UI again you don't have to do that but I will leave it like that since I think it looks actually quite nice another thing I will change right now is right here our logo so I will go in our navb right here and then where do I have it Marshall SAS let me wrap the SAS name actually in a span element and then I will give my span element a class name of text which will be primary if I now save it and go back you now see that my logo has changed and still everything works as it's expected so now there's currently one thing I don't like on the top right corner we have the lockout button and inherently it does not look that bad but we can make it way better we can show my profile image then we can have like a drop- down menu so we can make it way better so let's actually do that to do that actually what we have to do is go in the app folder in the components folder and I will create a new file called usern naav um. TSX now inside of here how do we start we start as we always do with an export function let's call it user um nav and let me open that inside of here now inside of here we'll need a few things only actually three components the drop- down menu the button and Avatar now currently we don't have the Avatar installed so what I will do is open a new tab let's go to ui. chan.com and then let's search for Avatar I will need that so let me click right here for the installation command I will copy it go in my terminal stop everything clear everything and then paste it to install the new Avatar now once that's installed let me actually restart my def server so right here it has installed Let's do an npm run def to restart our def server and now I can actually start coding my usern nav so let's create a return statement right here and let's start with a dropdown menu now it's very important that you import the drop down menu not from radic UI but from components and actually I don't mean just the drop down menu every component which we import I want you to import it from the components and not from RX UI because if you import a component from RX UI everything will still work there's no problem but the problem is that it won't be styled and we of course want our components to be nice and accessible so let me import a drop- down menu from our components and then inside of the drop- down menu we have to get a drop-down menu trigger now the drop- down menu trigger is again and import it from our components let's close that now inside of this drop down menu trigger let me actually give it also an attribute so the attribute will be as child now inside of the uh drop down menu trigger let's get the button now the button is again imported from our components and then inside of the button I want to get a avatar now the Avatar is again imported from our components then inside of the Avatar we will actually render a avatar image now the Avatar image is also imported from our components you saw I just uh mistakenly imported it from radx UI this is incorrect again from our components and this is in self closing tag now currently what have we done we have now imported a drop down and then inside of the drop down we have a button which is the trigger of our actual drop- down menu content which We'll add later um for now we have to actually add also in source for our Avatar image so let's give it in Source let's also give it an ALT property now for this Source let me actually just go to the shatan UI website click on code right here and let me just copy the image right here URL I will use it just for now temporary of course we'll later on change it to be dynamic let's paste it and let's see how it looks um yeah we don't see anything why is that well because we don't render the component anywhere so what I will do right now is go inside of our Navar component and now instead of rendering right here a lockout button let me just delete everything and let's just render our user nav element so let's import that self closing tag and let's see how it looks like yeah it does not look nice as you see we have a button a avatar somehow some weird stuff so let's change that let's go back to our usern na actually and let's start with the button I don't want to have it in background color and also I want it to be rounded so first of all for our button let's give it in variant the variant will be ghost actually and with ghost if I save it you will see the background color is not there anymore and now we just just have it on Hover then what else do we need let me also give it in class name now this will be relative h of 10 width of 10 and round it which will be full let's see how that looks like and yes you see this is now perfect now let's continue with our Avatar let me also style it let's give it a class name this will be h of 10 width of 10 and also rounded of full so very nice but now there will be one problem actually currently we render an image as you see right here which is nice but if we don't render an image so let me just comment out this Source right here so I will comment it out let's save it let's see and now you see we don't see anything it's like gone if we just hover over it we get in background color what is in simple fix actually under this Avatar image I can now render a avatar fallback with the Avatar fallback again imported from our components I just make sure if the image is not rendered for some case because we don't have an image or the image is corrupted I don't know we can just render an actual name so I can now just say Jan and if I now save it and go back you now see we render right here Jan which is very nice but now if I actually uncomment our image again and save it you will now see our image is still loaded again our Avatar fallback is only there if our image is loading not loaded or it's broken something like that but if the image is there our image will also load as you see right here so this works very nice but now the problem is if I click on this usern nav of course nothing happens and what we want to do is that we actually create a drop down menu so let's actually do that right now so under this drop- down menu trigger what I want to import now is a drop- down uh menu content now the drop- down menu content is imported from our components now let me actually also style it so let's give it a class name of w which will be 56 let's also do an align so this Sy same property provided by shat in UI this will be n and then let's also add right here a forse mount let's save it and now inside of this drop down menu content I actually want to render my name and also my email so right here what I will do is uh render a drop-down uh menu label again imported from our components now inside of here let me render a diff element and let's get an class name of flex Flex which will be call and space of Y which will be one now inside of here I render two P tags now the first P tag I render my name and then in the second P tag I render my email so right here for the name let me just say I don't know Jan Marshall and then for the email I would say Jan alex.de let's save it let's see how it looks like and yeah you see it does not look very nice but we'll fix that so right here for our pag let me actually say um class name text which will be SM let's also do a font which will be medium and let's also do a leading of number done let's save that let's see how it looks like yeah it looks quite nice now let's also style our email so let's give them class name this will now be text of XL and leading again which will be none and let's also do in text muted of foreground let's save it let's see and yes this looks very very nice in my opinion so now you see if I click on this user button we now get the name and the email but we're still not done what I want to now render is also actually the links so right here we have three links and that's exactly what I also want to do right here so let's do that so under this drop down menu label let's actually import the drop- down uh menu separator again from our components self closing tag we don't have to style it now under this drop down menu separator let me now import the drop-down uh menu group again from our components and now inside of this drop down menu group I want to map over my navigation items so right here let's get our nav items imported from our dashboard nav do map let me get the item and the index and then let me actually return that now inside of here let me now actually get the drop-down menu item again from our components and now we have to actually give it a few properties the first one as child and then the second one which is important is the key now we have to add the key to prevent any hydration errors and warnings and the key will just be our index now inside of this drop down menu item I can now render a link or the link component again from uh next SL link and let me actually also give it an H first of all so right here let's give it an hre this will be item. hre let's also give it an class name which will be W full um Flex justify which will be Center and let's also do items which will be also center now inside of this link element I want to render my item. name so let's get our item. name so if I now save it let's see see how it looks like and we get an error it tells me attempted to call map from the server but map is on the client now we could have course just uh actually adapt this component to a used client component but there's actually also a different way and inside of our dashboard nav I will just copy this export con snaf items let me copy it delete it from here and then inside of our usern Naf let me first of all delete this import and let me just paste what I've just copied so now first of all right here I have to import the home icon from Lucid react I have to import our settings from Lucid uh react and I have to import our credit card from Lucid react now right here we won't get any errors but for our Nash uh dashboard nav we now have an error where we don't import the nav items so let me import them from our usern nav and if I now save that you'll see everything still works and we don't get any errors anymore if I now click right here on the top on our usern nav you now see the free links now admittedly I don't even know how how to spell it here so whatever I mean this is how it's spelled um these current links don't look very nice so let's actually fix that um for that it's again quite simple let's go back to our usern Naf and now inside of our usern Naf let's actually first of all render also our icon so under this item. name where we render it let me also use an span element and get actually our um item do icon this is in self closing tag let's go a class name of W4 and H of four so now let me actually save it let's go back and yeah it does not look quite good so our link name and our icon are both centered in the middle now this shouldn't be our name should be actually on the left and then this icon should be on the right side and the fix for that is that right here I've said justify Center but it shouldn't be justify Center but it should be between actually and if I now do it like that you will see now it already looks thousand times better and it looks how it should look look now what's the next step the problem now is where we have changed this lock out button to this usern nav we can't lock out anymore so what do we do we now create a button so that the user can actually lock out so for that let's go back and right here we have our drop down menu group let me go under it and then right here let me again get the dropdown uh menu separator actually right here this is again in self closing tag and then under here what I want to now get is again the drop down uh menu item and then inside of here let me first of all give it in class name this will be again W full Flex justify again of between and then also items which will be of Center this is again the same class name that I gave the sling component right here so it shouldn't be any new thing for you also right here let's give it them property of as child since this is in child now inside of here let me actually render our lock out and then let's also get an span element and then inside of the the span element let me import an icon called door closed from Lucid react this is in self closing tag let's get them class name of W4 and H of4 now if I save that angle back we actually get an error react children only expected to receive a single react element child um what it says in basic terms is it expected one element but we actually pass the two elements so lock out and a span element what I could do right now is just wrap them in a different element and then the error will actually go away as you will see right now if I now click on it everything still works and we have now a lock out button but if I now click on this lock out button well nothing happens so how do we make the lock out actually work well if you again go back to our Naper element how did we make signing in and registering work well we used right here this loog in component and register component and now we need again this lock out link component so let me again uh copy this import statement since if I import that manually it would take too much time and now inside of our user uh nav let me just again import that and we only need the lockout link so import lockout link from kind o OSS kind of NEX shs components and now at the bottom instead of rending a link or a diff I'm sorry let's now render the lock out link so I will save that so now the time has come to see if the log out link actually works or the button works so let me click on it we should now get redirected to the index page and as you see that's exactly what happened this is very very cool and it fully works so let's again test it out let me click on sign in actually I should now get redirected to the kind website yes let me click on um actually continue with Google I will now log in with my Google account now what here tells me we can find your account and that's correct my Google account has hasn't been created right now so let me click right here on create account this will now take a second and and we should get redirected to/ dasboard and that's exactly what happened now there's one problem now we right now hardcoded the name and the email and also the image but we of course don't want to hardcode it we want to get the actual values so how do we actually do that that's again quite simple to do that I will actually go to the nav bar right here and we already get this is authenticated function let me now also get actually the get user function and let's you write here constant user and this will be equal to AIT get user now right here with this user if you hover over it and we now have an type of kind user and what I could now do is an user Dot and now I have uh a few options I can get the email the family name given name so the first name the ID and the picture and for our usern nav we want the name the email and the picture so what I will do is actually for the usern nav I will actually create an interface and then I will get these items through our params so let's actually now put that into reality let me again go to our usern Naf component and what I will do right here inside of the params let me the structure it I want to get a name I want to get an email and I want to get a image now this of course complains because it does not know what types these are so let me give a few types the name will be a string actually the email will also be a string and then of course the image will also be a string so let's save it and now you see we don't get any error anymore if I now go to the navb component it now actually complains it tells me right here that the following properties are missing the name the email and the image so let's add them right here for the usern nav let me right here give it first of all the email the email will be the user. email let's see write here an S string then the second property will be the image this will be the user. image or not image but picture as string and now for the name again we have two types actually if you again and check it we have the user. given name and family name um I will now just render the given name so let's you uh for the name right here um let's say user. given name as string so now this should work actually let's go back let me reload the page and we shouldn't get any errors first of all no we don't get any errors but we still don't render the live data so let's again go back to the usern nav actually and then for the user nav right here instead of using this hardcoded uh email let's use our Dynamic value of email then for my name let's actually also use the dynamic value of name and then the last thing the picture right here let me add the picture so this should be image let's save that and let's see if that works so I now will reload this page and now this is what you see you see the name and you see actually my email which is quite nice now you don't see the profile image and this is just a thing with Google Images if you you now actually go back to the nav bar and right here let's do a console.log and let's do user do um picture let me save that actually let's reload it right now um we get null so what I'll do right now is we quick just log out and loog in again with Google and now you see right here in the console actually the user image and now this is quite nice because now you also see the image right here so this now fully works as you see now let me delete the console.log again I don't need it and this is very nice so we now get the fresh name and also the fresh email and the profile image I can lock out and also click on all of these links and on the bottom left you also see that the link actually works so now since actually the usern nav fully works as you see we get fresh data and that our layout actually works so we have our nav links right here I think the time has now come to actually set up our database so in that sense um super base and Prisma to make querying work and also to store our users which we right now create also in our personal database so I think the first thing we should do right now is head over to superbase so I'm now at superb.com and if you didn't know superbase is actually an open source alternative to Firebase and we'll use superbase actually to get a post database so to get started I will WR you click on the top to dashboard and then right here you see I'm now in the dashboard so let me create a new project let me choose my organization then for the project name I will just say Marshall says um production because this will be my production build let's generate a password I will copy this password actually let me go to myv file and I will just paste it right here because I will need it in a second and I will leave the region actually in the US since my application will also be hosted in the US and it's always nice if the data and your application are both hosted in the same region so now let's let me click on create new project this will take about a minute or two and while this project is being created let's actually install Prisma in the meantime now what is Prisma well Prisma is actually an OM which we'll use and with Prisma we'll then query our data uh mutate our data Etc so it's just in types safe orm and it's quite nice to use so to get started I stopped my def server and now let's do an npmi um- D Prisma now this Dash capitalized d just tells um I guess the CI our project that this is in development dependency and should only work in the development environment and that means when we deploy our application to production so to verel um Prisma or the actual application size won't be applicable to our total bundle size so now let me click enter so Prisma has been now installed now we also need npmi at um Prisma SL client so now both Prisma and a Prisma client have been installed so now I can do an NP Prisma in it and also one thing is if you don't want to type out installation commands manually of course you can open my actual YouTube description or get up um read me whatever you want and just copy the um installation commands from there if you want to and now you see we have actually initialized pisas so it tells us right here warning you already have a git ignore file don't forget to add EnV into it we already did that so we can St uh skip this step now the next steps are to set up a database URL and and then create our schema Etc so if I now just open actually my EnV file or we are already in it you right here now see we have created a new environment variable and this is the database URL now currently the database URL is just in default non-working example but we of course will change it in a second to our superbase URL another thing that has been created by Prisma is the Prisma folder with a file called schema. Prisma in the schema. Prisma file our schema will live so all of our models like a user model a um notes model or also our subscription model so we then just store our data based on our schema or based on our models however you want to see it um let's now check if super base is done initializing and I think it's almost done I can right here click on Project settings then I can click on database so right here at the top we now have our connection string and that's exactly what we need so I will click right here on copy and then let's go back let me go back to the inv file and let me delete this whole string actually I've now pasted what we have just copied so our database URL and now there's actually one important thing right here right here we have your password and if you can remember I've copied my password here so let me copy it again and now paste it to this your password so delete everything and also these array brackets and then paste your password so I've now done that and this should now actually work now the next step which we can do is actually U model our schema so we could create our first model which will be the user user model so let's start with that let's give it a model the name will be user and now let me open that now right here it actually complains and why does uh Prisma right here complain well it's actually quite simple each model needs an ID that's uh actually quite simple you always need that with relational databases and that's why it currently complaints so let's give it an ID and let's give it in string let's also do an add ID and add unique since uh each ID should of course be unique then let's give it a name since our user of course has a name let's use string um right here I add a question mark with that I just tell pisma hey this does not have to be defined it can be defined but it can also be undefined then the next step I want to add is the email this will be a string and this will be also unique since each email should be unique then the next step I want to have or the next I guess field is the stripe um customer ID now this is currently not very interesting but later on um I will actually show you why we need it now now the strip custom ID is also optional and should actually also be unique so let's do an add unique and then the last field for now what I want to add is the color scheme so later on in the settings we can actually change the color scheme uh which the user wants so let's do in color um scheme this will be also a string now this won't be optional and let's also do an add default so that I always have it default and this will be theme- orange now I want you to spell it correctly please be sure that you don't misspell it so now we have created a model user but now currently this model only lives in our database or not in our database I'm sorry but in our project if you go to super base and click right here on the table editor you see we have zero tables but right here in Prisma we have one table or in model the user model so how do we change it how do we get this local um table and push it to our remote database well it's actually quite simple I will open my terminal let me clear everything and let's you npx pisma DB push to push our um schema to our remote database which is super base so now we got an error right here schema engine error um error prepared statement S zero does not exist now this is actually the first error or the first time that I've seen this error and that's actually because if you go again to the project settings and to the database and right here they now have changed actually to use something called where is it supervisor and now uh also the URLs have changed and actually if I go to GitHub right here someone commented that you actually just have to delete this um number and SL uh post grass so all I will leave is the superb.com at the end and now let's see if this works so npx Prisma DB um push let's see this should now load again let's see let's see let's see and now you see we did not get any era anymore so all you do is again right here just delete this uh number and SL postest now I don't know why this is is added I don't also really care but now it's fixed so this works now perfectly if I now actually go to super base so let me uh uh close this skup comment again and go to the table editor you now see we have one table and now this table is our user table with this Fields name email stripe custom ID and customer uh or color schema so you see this now works so let me again start my def server so I clear everything and again do an npm1 Def and before I can use our Prisma client to query our data or mutate our data there's one problem um you can go to Google and actually uh Google for Prisma nexs best practices and you will see that the problem is um nexs uses HMR so that means actually if you save your code um the bundles get actually reloaded so we have hot module reloading and the problem with that is that we actually create a new Prisma instance or a new instance of Prisma client and you don't want to do that in a development environment so what you do is actually create a global Prisma file in the um prod uh development environment and then in the production environment you create the normal Prisma client so what I'll do right here is just copy the uh code right here and we have a file that we will name db. TS so what I will do right now is go inside of the app folder let me create a new file called or not a new file but a new folder called lip and then inside of here let's create a new file called db. TS I will now just copy this code right here and pasted inside of here and again what do we actually do right here well we check if we in a production environment and if we are in a production environment we set our Prisma um client to a global environment or to a global Prisma client but if we are in a uh production environment we just set it to the normal new Prisma client and it just generates a new instance so now I hope you understand why we do that and now we actually have set up Prisma so we have created our schema we have created our connection string and we have created a new Prisma client when we are in the development environment so what do we do now uh did I already start my Dev server yes so let me again open that in Chrome let me close this um Prisma docs actually since we don't need it anymore now this currently reloads so let's see so now you see already one problem so I'm currently signed in as you see right here I have my usern na where I can log out but I'm still in the index page as you see right here now I don't want to do that actually what I want to do is when I'm signed in I want to get redirected to the/ dashboard route and if I'm not logged in of course I want to get redirected to the index page to sign in so what I'll do right now is actually let's go back to our page. TSX so our index page and then inside of here we can actually get our session again and then with that we can actually check hey do you have a session if yes let uh let us redirect you to the dashboard and if not let's just stay right here so how we do that again if you go to your NAB bar. TSX you already did it right right here we have right here this get server session function so let me just copy the import statement right here again let me paste it right here so this is import get kind server session from kind OSS s kind of nextjs server and then right here I can initialize it or I can get an other function so let's do in constant let's destructure it uh this will be equal to get um kind server session and now inside of here I want to get the is authenticated function now it's important that we have to mark our um function right here so our export default function as an async function so let's do an export default async function and then now right here what I'll do is an if statement and if a weight is authenticated is true so if we have in session let's you in return redirect now redirect is imported from next SL navigation and not from this weird distribution import whatever that is so from next SL navigation and I'm sorry this is the wrong import again so again redirect next navigation and then inside of here I actually have to pass the URL where we want to redirect and right here I check is the user authenticated and if the user is authenticated Let's uh redirect the user to slash dashboard if I now save that and go back you see right here if I reload the page we should get redirected to/ dasboard and that's exactly what happens if I now again try to reach the normal index route so I will try to do that you'll see we again get redirected so now this for works but what happens if the user is not authenticated let me open my new incognito tab let me go right here let me copy this URL and let me actually paste it right here you see even though I'm not signed in I can still reach the/ dashboard route and this of course should not happen so I think it would be actually quite wise to fix that right now so what we'll do right now is right here let me again copy this import statement so this import get kind server session I will copy that then let's open our Explorer go in the app folder go in the dashboard and then in our layout. TSX and now inside of here I want to get our session so on top let me again just uh paste our import statement of get kind server session and then right here in our export default function let's just do in const let's the structure it this will be equal to get kind server session and now inside of here I don't want to get is authenticated but let's do and get user because I will need it for another thing in a second then we of course again have to Market as an async function because if I would do right here in const user equals to AIT get user you'll see we get an error and it tells me right here a expressions are only allowed with an async functions so let's export a default async function and now you see we don't get any errors anymore now what I want to do right here now is check if we don't have an user then we'll just redirect the user again to the index route to authenticate so again how do we do that well on top Let's do an if no user let's just open that and let's do in return redirect again redirect imported from next SL navigation and then let's just uh redirect to the index route if I now create again another incognito tab so let me create a new one paste right here our dashboard route let me click enter and as you see I got uh automatically redirected to our index route um from the server so we didn't see any flash or anything like that everything works very very nicely so now you see um if I'm signed in I can't actually reach um the index page and if I'm not signed in I can't reach the dashb route so now this works so what's now the Second Step which I want to do well if you actually right now check so let me go to kind actually right now to the kind dashboard so now you see I'm in the kind dashboard and now the thing is that currently you see right here I have two users which is quite nice right but another problem which I have is if I open my terminal click right here here on new terminal Tab and then inside of here let's do an npx Prisma Studio this will now open the Prisma Studio where we see our database actually so this loads right now for me as you see right here let me wait for that now right here you see it loads and it should now open and now the problem you see is that we in total have zero actual fields for our user model so inside of our database we have zero users but in our Cent database we have actually two users so how do refix that actually because what I want to do is of course also uh create our users or my users in my database to query it from my database well it's actually quite simple we'll create an Asing function with which we will just get uh our user data and then we will check if we don't get the user data from our database we'll create a new user in our database and if not we'll just continue so right here above our dashboard layout let me create a new async function and let's call it an let me first of all spell that correctly let's call it get data now let me just open that function and now inside of here we can actually get started so first of all through the params I have to get the email ID first name last name and profile image so let me actually destructure it and let me get right here the email let's get the ID let's get the first name let's get the last name and then let's also get the profile image now right here um actually typ script complaints and it does not know what type email ID or first name have so let me actually give them a few types so our email will be of type string then our ID will also be of type string then our first name will actually have a few um types so it could either be a string or it could be undefined or it could be null and we're still not done we now have also the last name in the profile image for the last name actually this will be again the same it will be either string undefined or null and then the last one which we have the last type is the the profile image and this is also either a string undefined or it could be null so now let's save that and now you see we don't get any errors anymore now inside of our Asing function we can now actually use that data so let's right here do a const user this will be equal to arrate Prisma now it's important that you don't import Prisma from at Prisma client but actually from our Prisma file or from this db. TS file so right here it sadly does not automatically import for me so on I will do an import Prisma and this will now import from lip um TB so now this works and let's actually continue so arrate Prisma do user. find unique and now let's see let's do in where statement and I want to find an user where the ID is actually matching to the ID which I passed let me also select a few things so I want to get actually a ID so let's do ID of true and let's also get the stripe custom ID and let's also set that to true so so now this looks very nice we now fetch our user from our database and we select the ID and stripe custom ID now what I want to do is an if check so if we don't have an user I will create a new user and if we have a user I will just do nothing then right here we do an if no user and for this no you just use this uh exclamation mark So if we have no user let's actually do right in await and Prisma do user. create since we want to create a new user then we have to pass data we'll give it an ID the ID will be equal to ID we'll give it an email and the email will be equal to the email then let's also right here get our name so right here that's our name now the problem with name is currently right here we get a first name and the last name so what I want to do is actually combine the first name and the last name to One Singular name so what I'll do right here is let's create a new constant let's name it name and this will be equal to let's use Optics and then inside of here we'll get our first name and if it's not defined let's use u a double question mark and let's just say an empty string and then also let's get our last name right here and if this is also not defined let's also just use an empty string and now right here for our name I can pass the name so now this should actually work so what I'll do right now is let me actually stop my Prisma uh studio right here I will cleared and um delete this terminal tab let me also stop our death environment right now and let me go back to the kind database then I will click right here on users and delete my total two users right now so let me do that real quick so right here I will just click on the three marks then click on delete user and then delete all data and then delete user this will now delete the user and then we won't have any users anymore in the kind database so now I can actually head again back but now before I actually go and uh restart our def server that's one important thing this Asing function get data currently does not run and that's because we actually also have to first of all call it right here in our um dashboard rout layout so under this if no user exists let's do await get data and then right here you see we get an error and that's because I now have to pass my email first name ID last name and profile image let's start with our email this will be equal to user. emails string then the next value will be the first name this will be equal to user. given name as string then the next one is ID this will be equal to user do ID as string then the next field will be the last name this will be equal to user. family name as string and then the last value which we have is actually the image so let's right here get our profile image and this will be equal to user. picture so if I now save that this will actually work again so let me again restart my Dev server right here so let me do an npm run Def and actually let me also again open my new terminal Tab and run npx Prisma um studio so this will now restart my studio again right here let's go back to my def server let me actually restart it again so now my def server has again restarted I will again click on sign up now sign up not sign in why is that well that's because we have deleted actually the accounts in our Cent database and the facto we don't have any users anymore I can now continue with Google actually so right here you see we get an error so now what the problem is actually right here we currently have this URL and if I go back to the docs right here they have created a new docs page it has now changed a bit so we now have to actually change our URL and at the end we have to actually right here at our PG bouncer sh and connection limit one so the first thing I will do is go back again I will copy this whole database Ur again I will delete everything right here in this database your L string paste it again then I already forgot my password so I I will again go right here and click on reset that uh password generate a new password and then click on reset let me first of all copy it also right here then I will go back and then right here in our array brackets I will now add the password right here so now this has been added now we're still not done if I go back to the stocks page um again right here we have to add this PG bouncer true and connection limit one so I will now copy that and add it right here at the end I will save that now we're still not done I know I wish I would be done but no um if we now scroll down we now have a database we added that now we also have to add an direct URL so I will now copy this direct URL and paste it also right here to my EnV now for the direct URL it's almost the same I will again just copy everything from here paste it back now right here all I have to do is actually delete everything after this slash poost Quest so it will just be at the end/ poost quest we're still not done we still now have to change the number to 5432 so I will copy that and paste that so all we have done is actually just we took the same URL but we changed the number to 543 uh 5432 / postgress and we deleted this PG bouncer true now we're still not done if I know scroll down we now also have to tell that our schema actually so right here we have to pass a direct URL so let me actually copy this right now let's go to our schema. Prisma and right here for our data source DB I will also add add that now let's see if there is still anything different nope I think this should now actually work so let's see I will clear everything let's test it out uh test it out with an npx Prisma DB push let's see if that works do we get any errors and now you see it finally worked so now our database actually works with the correct um actual database or environment variables now we again have to do everything the same let's again go to kind I will again delete all of my users in my death environment let me lock out first of all or our death environment is even not working so let me actually right here just first of all delete again my users and then we can continue so I've now deleted my user for my Cent database I can again clear everything let's see does our studio run no let me start my def server with npm1 def this will now restart again on loow CL 3000 and then also in the meantime let me also start with an npx Prisma studio so right here let's do an npx Prisma Studio this should not also open right now so let's see this open right here our death environment also opened let me now click on sign up and I will again play the same game I will continue with Google and now let's see if this actually works so let me do that now I got an error right here currently because my database was not empty so what I'll do is again just um let me reload this page right here this should reload in a second let me sign out from here again lock out so now what we have done is we have I have cleared my database completely I have no users anymore let me again go to the kind database also delete my users from there so now let's start again fresh I have deleted all my users from kind let me also delete my user from my Prisma database right here or from my superbase database let me again reload it just to be safe that everything is actually deleted because I don't want to get any errors let's see let's see let's see it's fetching and no rolls so now actually I have no users anywhere so now let's again test it out I will click on sign up so I will again sign up with Google let me do that and now you see I got redirected to/ dasboard and if I now go back to my database I will actually reload it right now I should see one user and let's see it's currently fetching the rose and then right here you now see me so uh I'm the user and now you see me right here now let's see if I actually lock out and now sign in so I don't create an account but just sign in let's see if I get any errors there so I will Contin continue with Google so now you see I signed in with Google and still everything works and if I now head over back to my database I now should not see any duplicate users and you see I still only have one user and that's still only me so now you see this finally works now let's again go uh over what we have done I know it was a bit annoying also for me actually because again super base uh has done a few weird things so first of all we have now created a new database URL we had right here now to give it right here the 65 or 3/ postgress and then also give it an uh PG bounce of true and con connection limit of one y connection limit of one that's just a thing that we need for serverless environments then also we have to give it a direct URL this is there to actually create migrations so when we do an npx Prisma DB push we need this direct URL so now that's what we have done and then in our layout if we check it right here now what we do is we fetch our user we see hey do we have a user if not no let's create a new user and if there's an user just skip that completely and let's continue so that's now what we have done so we've uh check if we have a user then we create a user and now everything works so what do we do now I think the next thing we should do right now is actually create the settings page and then in the settings page the user can change the name and also the theme that we use right here so currently we use this orange theme but what I want to do is that the user can actually also change to for example a blue theme or to a pink theme whatever the user wants so let's create the settings page so now to create actually the settings what we have to do now is actually go inside of our Explorer in the app folder in to the dashboard and then create a new folder called settings now inside of this folder I will create a new route with page. TSX now how do we always start well it's quite simple we create an export default function so let's do an export default function let's name it um settings page and then let me just open this function inside of here I will return something and let's say div with an H1 and let's say um hello from the settings page let me save that let's see if everything works so I will now click on settings we should now get redirected and yes you now see hello from the settings page and also right here for our link nav you now see that the color has changed to this grayish color and you see now that we on the route SL dasboard SL settings and that's why we have this uh background color right here so this route now works so let's actually now also create that route so that everything works so let's go down right here or let's go back to the code let me delete everything let's create a new return statement with a new diff element and let me give it a class name which will be grid items which will be start and let's also do in gap of eight then inside of here I will create another diff element let create in class name which will be Flex items which will be Center justify which will be between and then also a padding X of two so padding on the horizontal side then inside of here I will create another diff element let's give it a class name of grid and gap of one and now this was the last diff for now so inside of here I can now render an H1 and let's just say settings and then inside or under this H1 I render P tag and let's just say your profile settings let's see how that actually looks so let me go back this reloads and now you see settings and your profile settings now this is of course currently not styled it does not look good so let's change that so let's start with the H1 tag let's give it a class name so then right here let me do in text which will be free XL let's do medium of text which will be for Excel and let's see how that looks right now and yes this looks already quite nice now our description does not look so good so let me also actually style that let's get in class name this will be text of LG then text of muted foreground and this should be all let's see how that looks and yes this looks also quite nice if I zoom out a bit for me it looks better but if it's zoomed in it looks also quite nice right now so now let's actually create the settings card so I want to have a card where then the user can change the name and the color preference and how we do that well we will go under the pag and under the uh next to diffs so just above the last diff and now let's create the card so we'll use a card component and we haven't installed that so let me go to ui. shen.com and then we will need the card component so let's search for the card component let's right here install it so I will take the installation command I will copy that let me actually create a new terminal tab right here let me actually stop the Prisma Studio I don't need it and let's paste this Command right here now we'll install the card component also while we are here let me also install the label component so right here let me copy the installation command with npm let's paste that let's also get the um input right here so let me also copy the installation command paste it and now I think this should be all input label ah I forgot one thing that's the select component so let's get the select component I will copy the installation command and let me just paste that so now we added the card the label the input and the select component and now we can actually use them right here so let me uh get the card component imported from the uh components that and inside of here let me render a form element now I will delete the action for now we don't need it right now then inside of here let's get the card header component from our components and let's create a card title now the card title is of course imported from the components let's say General um data and then let's also create a card description so again this is a component imported from the components let's just say um please provide general information about yourself um please don't forget to save let's save that let's see how that looks so I will go back let me reload the page just to be sure and now you see this card right here with General data and please provide general information about yourself and let me see how it looks like in light mode and yes it looks quite nice so let me again change it to dark mode because it's a bit easier on my eyes and now we can actually create the card content so under the card description or actually under the card header I will create now the card um content component imported from our components and then inside of here let's use a diff element let's give it a class name and this will be space of Y 2 and then inside of here I can render another diff element let's give it a class name this will be space y of one and then inside of here we can use the label component import it from the components and then let's just say I don't know your name under that let's use the input component again imported from our components then inside of here let's give it a name the name will just be name I know quite redundant but whatever let's give it in type this will be a type of text let's give it also an ID for uh which will be name and then let's also do a placeholder and this will just be your name let's save that let's see how that looks like um this reloads right now and yes in my opinion this actually looks quite nice your name and also right here placeholder and our input as you see so this looks quite nice then the second uh actual input and label which I want to have is for my email so I will just copy the stiff element right here with the space y1 I will copy and paste it then right here this shouldn't be your name but now your email for the name let's say email for the type this will be also email for the ID this will be email and then for the placeholder your email let's also make it disabled so I don't want the user to be actually able to change the email and later on we'll give it a default value of the current email let's save that let's see what it looks like um this should be load let's see and yes this actually looks quite nice and the last field which I want to have is actually the select field where the user can select a color so under this diff element let's create another diff element let's create a class name which will be space y of one and then inside of here let me render again the label and let's just say color scheme then under the color or under the label I'm sorry let's now render the select component imported from our components uh let's actually give it a name right here so let's say name of um color lowercase and then inside of the select component let's um actually get a select trigger now the select trigger is imported from our components then inside of the select trigger let me first of all give it a class name of w full and then inside of here I can have a select value and this will be actually in self close cling tag and now what I can do right here is give it a placeholder and this placeholder will just say select a color now under the select trigger let me actually render the select content again imported from our components now inside of here I will render a select group also imported from the components and now inside of here let me render again a select label and then inside of here let's just say colors and then under here let's do an select item this is imported from our components and let me just say green let me also give it a value right here so let's do in value and let's just say I don't know theme of green let's save that let's see how that looks like and I get an error um I think the error is right here because I um mistakenly import select label and select value from RX UI what I always preach not to do so let me again delete that let's import that again correctly from our components right here from add components and this also from add components if I now save that actually and go back let me actually reload the page right here just to be sure that everything works and now we have right here in select field with select a color and also then within value which is green let me now add a few more values so I will just actually copy and paste it a few more times then the next value which I want to have is blue then let's also do Violet let's also do under that then yellow under that let's do an orange Under that let's do a red and then the last one will be Rose Also let's do that for the value the first one will be theme green then the second one will be theme blue then theme Violet then theme which will be um yellow then let's do theme of Orange Let's also do theme of red and theme of um Rose so I will now save that let's see how that looks like let's save it let's click on that and yes you now see all of the options right here so green blue violet Etc so this fully Works let's see how it looks in white mode actually so I will right here click on light mode and yes this also looks very very beautiful so now let's actually make this whole um actual settings page work and for that we first of all have to fetch a bit of data so on top Point here I will again create an async function let's call it get data and then let's open that now inside of here I want to again fetch data for the user so let's do a constant which is data this will be equal to a now Prisma again is imported from our lip folder so on top let's do again an import Prisma from our lip folder then let's do in Prisma do user. find unique and now inside of here I want to find a user where the ID corresponds to the current user ID now I first of all of course have to get the user ID so on top in the params let's get an user ID this will be of types swing actually and then I can pass the user ID right here now what do I want to select from the user so let's do WR here in select statement and let's get the name so let's set that to true and let's also get the email so let me set that to true and also the color scheme actually since I want to get the value and this will be also true let's now save that the last step is to return that data and now we can get that right here in our component so let's do in constant data this will be equal to a get data and now we get two errors the first one is uh the normal error which we always get that arrayed expressions are only allowed with an async functions so let's do an export default async function and then also right here for get data we get an error that it expects one argument but got zero What's the argument well the argument right here is the user ID so we have to actually first of all get the user ID and we do that again with our get kind server session so let me again import our get kind server session function so I'll copy the import statement from our nav bar let me paste it right here then right above this cons data a r get data let's do constant let's D structure it this will be equal to um get kind server session and inside of here what I want to get is the get user then under that let's do a constant user this will be equal to AIT get user and now right here for our get data function I can actually pass the user. ID as string so this will now actually fully work and we now fetch the data but we're still not done I of course now also want to show the data right here so what I can do right here for the name is get an default value and let's just say right here data do name and if this is not the let's just do an empty string and then we get an error right here and it tells me typ string null or undefined is not applicable to typ string so what I'll do right here is just if this is not defined so if this double uh question mark let's just do an undefined so this now fully works as you see then for the email let me also give it right here in default value this will be actually data. email as string this should work let me save that let's see how that looks like so now you see my name right here and my email and this fully works now let me also get the color scheme so for that right here for the select I can also give it in default value and this will be actually data do color scheme let me now save that let's see how that looks like you should now see right here orange so this reloads or let me reload it actually so let's see and now you see right here on the bottom orange I can of course again click on that and then you see a question mark or not a question mark but a check mark for the orange color so now we get the data for the name for the email and also for the color this is very very nice now what's the last step which we need well of course we want to change the data and then save the data so we need on the bottom left corner a button to submit the button how do you do that that's again quite simple so right here just uh below this card content I will now use the card um footer component from our components and then inside of here I want to now have a button so let me import a button from our components and let's just say save now I will now save that and let's see how that actually looks like and now you see right here on the bottom left corner a save Now button let me zoom out a bit just for my taste a bit and yes I think this looks quite nice now what I think we should do is actually make the mutation work so that the user or in that case that I can change my name and also change my color preference so let's do that right now now for that I will actually use an server action and they are quite nice in ex shs since I don't have to create separate API routes but I can write the server actions directly in file so right here let let me do an async um function let me name it post data and then let me open that now I get an error did I misspell async yes I did now currently there's one problem this async function is currently just a I guess a normal async function which runs on the client now we of course don't want to do that we want the server action to run on the server so right here let's mark it as use server and with that we tell next shares or in that sense react that hey this um Asing function should only run on the ser server and never on the client also in the params right here I can get all form data this will be of type form data and then with the form data I can get the actual values from our form right here also I can give our form now an action this will now be the action of post data so of our server action now right here for our server action Let's do an arrate Prisma do user. update since I want to update the user now we of course have to do in wear statement since we want to update a specific user so I want to do where the ID is actually equal to the user. ID then we also of course have to now create a data statement and I want to update the name and then I of course also want to update the color scheme so right here let me get the color scheme and set it to an empty string for now so now I have to get our name and the color scheme value from my form data how do you do that that's quite simple right here let's create a constant this will be equal to name and this will be equal to form data doget and now I want to get the specific I guess um input which corresponds to the name let's check it out right here we have an input and we gave it a name so the name is called name and what I can do right here is just do uh form data. getet name and with that I just get the value of this input right here I can also do the same for the color scheme so let's do constant which is called color scheme and this will be equal to form data. getet and now I want to get the color scheme so where is it it's right here we right here give it gave it a name of color so I again just can do in form data. getet color and with that I will get the value of the select field now for right here in our Prisma update I can now just pass instead of an empty string our name and if there is no name Let's do an undefined so with an double question mark now let's also do the same for the color scheme let me do color scheme and if that's not defined Let's do an undefined now we get two hours right here and it tells me form data entry is not app cable to typee string so what we will do right here is an as string and then also the same for our color scheme so as string if I now save that we don't get any errors anymore and now this is quite nice I think it's now actually time to test out if it works so right here for the button let me actually also do it in button or in type which will be submit to submit our form and now let's see if this works so let me reload the page just to be safe actually um now this has been Reloaded and now let me change my name I will just say Jan Marshall and let's change the color to I don't know yellow now let me click on Save now this should be now actually posted to our database and now let me reload the page and see if this works so is my name persisted this reloads and you see Jan Marshall and color scheme yellow so yes this is actually persisted but now we have a problem we don't really have a user feedback so what I want to do is if I click on the button save now I want to have a loading indicator so what I can do actually is open my Explorer again let me go in the app folder components folder and let me create a new file called submit um buttons. TSX now inside of here I will have to mark it as use client why will I have to do that well I will have to get the pending State and to get the pending State there's an function called use form status which only want on the client so let me Mark this file as use client actually and then under that let's do an export function let's call it um submit button and let me just open that function inside of here let me do an return statement let's use empty brackets Right Here and Now what I want to do right here is check hey do we have currently have a pending event so do we currently submit if yes let me return a button where it just says please wait and if no let's just say save now and for that we have this uh nice function let's do in constant let's D structure it and this will be equal to use from status again imported from react dor and right here I can now get the pending State and then with the pending State this is some Boolean I can check hey does it uh is it currently pending or is it not pending so right here let's use intern actually so if pending is true let's use some question mark and uh return something and if this is false let's uh use some colon and return something else so if this is true let's actually return a button right here imported from our components and let's just say please wait and if this is not true so we don't submit currently let's create another button right here and let's say save now and let's also give it in type of submit if I now save that we first of all don't get any errors anymore and I can now actually use this button in our pending or in our settings uh page so right here instead of this button of save now let's actually now use the submit button component imported from our components let's see if we get any errors I know you still see everything works perfectly but I of course don't want to leave it like that I just don't want to have a please rate and a safe now this is a bit boring because we can test it out actually let's change my name just to Jan uh Jan right here let me click on Save now you now see please wait and when the pending state is done uh the button again changes to save now but this is not quite eventful in my opinion it's not that nice looking so let's again add a few things so if this is pending let's give it also in disabled state let's give it a class name of wfit and then right here for please wait I also want to have a loading indicator so just above this please right text let me import a loader to icon from Lucid react this is in self closing tag let's get in class name of margin right 2 W of four h of four and animate of spin let's save that and then for the second button so if it's not pending let me just give it a class name of wfit Let Me Now save that and now let's see how it actually looks like let me now give it a name of Jan Marshall so my name and then let me click on Save now and now you see this nice very good looking pending State and you still see everything works because if I now reload the page my name and also the color preference should cap persisted and that's exactly what happens let me now change the color again to uh green for example let me click on Save now we again have this beautiful pending State and everything still works now currently we have the following problem so even though everything works we have the save Now button I can change my name and I can change the color schema and both of these values are stored in my database my problem is now if I actually change the color scheme you see that the page itself does not update I still have this orange theme which looks nice but that's not the intended use case of a color scheme selector so how do you actually change it now this is actually not that simple but let me show you so currently if you go in our layout. TSX so this is the layout file which actually wraps all of our children right here we have our body element and if you now open our global. CSS CL um file you will see right here our at layer base with the root Styles and then the dark styles for our root element So currently whatever we have right here applies to our um body element so right here again this element right here so right here for this class name but I want to change the body element class name dynamically or the theme actually dynamically based on the user's preference so what I have to do is actually fetch the user's um color preference right here in this layout file and then actually just append it to the body class name so what I'll do right here is delete this at layer base so this one right here but I'll still leave this with the border and also BG background that's fine and I also will leave this at T classes because we need them and now I will paste a bit of styles what I want you to do is go to my GitHub and just copy them from the global. CSS file but what I did here right here is for example the theme Rose and then the Dark theme Rose the theme orange and then the Dark theme orange Etc but what would happen now is if I save this file and I test it out you see we don't have any Styles anymore and that's because I don't actually Target the body element anymore so how do you fix that so first of all let me copy this inter. class name let's use Optics and let's render it right here inside of this element and then the next thing I have to do is actually right here now give it the class name of what theme I want to use so for example let's just hardcode it to theme- Orange let's see how that looks like and now if I reload the page you should see that we now have again the theme which is this orange theme or this orange color but now let's say we want to get it dynamically so what the user actually selected right here in the select menu so for that we'll actually create right here an async function so let's do an async um function get data let me open that I misspelled async so let me spell that correctly and now inside of here I have to get actually the color preference of the user so let's do in const data this will be equal to a now I have to import Prisma so on top Let's do an import Prisma I will import that from my lip folder and then right here let's array Prisma do user. find unique then I have to find in user where the ID matches the ID which I pass for that let me go to the params and get an um user ID this will be of type string and then I can pass it right here user ID and then right here let me just do in select statement and I want to select where is it the color scheme so let me set it to true now let's return that data right here return data and now we have to actually fetch it in the component or get the data in the component for that let's do in const data this will be equal to a get data and now we get two errors first of all a expressions are only allowed with an asnc function so let's do an export default called async function root layout and then also for get data we have to pass an argument which is the user ID for that we actually first of all have to get the user ID so let's again go to the nav bar and then right here we import this get uh kind server session so I will copy this import statement and also import it right here inside of the root layout let me add the I for import so good that looks nice now right here above this Con data let's do in con let's D structure it and this will be equal to get kind server session and what I want to get is the get user function now what I can do right here is a const user equals to ARR get user and then right here let me just pass the user. ID as um string actually and what I can do now is actually right here instead of hardcoding theme orange let me again use the dynamic value right here of data do color scheme let me now save it and let's see if it actually works so let me go back let's reload the page and as you see see I now have this uh green theme right here but what happens if I change it so let me change it to red right now and let's click on Save now and what will happen well weird right it does not change to red but if I do now in hard refresh you will see it will actually change to red right let's see let's see you see a change to red why is that well that's because server components are actually cached and what we have to do is we validate the cache so that we actually see uh this update right here so the color change so for that there's an handy function let's first of all go to the settings page again so right here and what we have to do right here now is inside of this um server action where we post our data we have to revalidate our data so what we can do is and revalidate path this is provided by next so you import that from next slash and now we have to actually pass or tell this function what you want to revalidate so right here we actually have to pass the route or not the route but the path which we want to revalidate and we want to revalidate the root layout so that means we want to revalidate the whole application so what you'll do is give it in route path of Slash so the index page and comma and then say layout so I want to revalidate the root layout so let's go back let's refresh the page again and hard refresh and now I will actually choose another color we have red right now let's do uh Violet why not I will click on Save now and this will now automatically revalidate actually and we'll see now that the color is updated without me hard refreshing so now this works beautifully but what happens actually if the user is not signed in so I will again go to an incognito tab let me just copy this URL right here and let's paste it inside of here so right here we now get actually an error it tells me right here a argument where of type user where input needs at least one of ID email or stripe custom ID so what exactly does the eror tell me it tells me right here if I go to the layout really quick let me open that it tells me right here that I tell uh this a get data that I have an user ID that it's defined but this is actually not true because the user ID can be undefined it could be that we don't have an user so now what we'll do is actually let me copy it so what I'll do right here is actually an if statement and if we have an user ID then I will fetch this data but if there's no user ID I won't fetch anything it's that simple now I will copy again this return statement and just paste it right here now if I save that go back to my incognito tab and do an hard refresh you see now we see actually in page but now we have another problem we don't have any Styles so how do you fix that well it's again quite simple right here we assume that we get a data. color scheme but as you see right now this is not true we don't get any color scheme so what we can use is this double question mark again where we just say hey if this is not defined use another value and we will just hard Code theme- Orange let me save that let's go back let's do hard refresh and now you see even though the user not signed in I still see an orange theme and the website is not ugly so we have a default of orange but the user can always just change the theme if the user wants to do that so you see this works perfectly and now we actually are able to change the theme dynamically let me again change it to Orange because why not so here's orange I will click save now we have the loading indicator and it will now validate the cache and we see that the theme has changed beautiful right so this works perfectly our settings are now done and I would now say the next step has come to actually set up bilding so let's do that so to create the bilding page what I'll do right now is go inside of the app folder inside of the dashboard folder and then right here let's create a new folder actually not a file and this folder will be called building now inside of this folder let's create a new file called page. TSX since we want to create a new route of course and how do we always start right here well we have to export default a new uh function so let's do an export default um function we'll name it bilding page and then let me just open that now inside of here let me return something let's say diff and H1 and let's say hello from the billing page let's save that let's see if that actually works so I will now click on billing and we should get redirected to slbo bilding that's exactly what happened and now we have hello from the bilding page also you see that this billing nav link actually also has this highlighted with a uh background color so you see this fully works so if I click on home you see the background color if I then click on settings we also have a background color and if I click on bilding we also have a background color so this is very very nice so now I think we can actually create the um pricing card so the pricing component so let's actually do that so right here let me first of all delete everything in the return statement since I actually don't need that we'll start off fresh how we always do so let's right here start with in diff element let me give it in class name this will be Max width of medium MX of Auto and space y of four then inside of here I want to now render my actual pricing card and for that I will use a card component imported from our components let me also give it actually a class name and this will be flex and flex call since I want to stack the elements vertically and not horizontally then inside of the card uh card component let's now import card content again from our components I will also give them class name and this will be padding y uh so padding on the Y AIS of eight then inside of here let me get an diff element and H3 element then in this H3 let's actually just say monthly let's see how that actually looks right here yeah it looks all right but we have to of course style it a bit so let me style the h tree let's go in class name this will be inline of FX padding X which will be four padding Y which will be one then let's your rounded which will be actually full text which will be small font which will be semi bold tracking which will be white let's also do it uppercase and then BG primary sl10 now what does the sl10 mean well actually this just says hey give me BG primary so this um I guess orange color but only give me opacity of 10% so not an opacity of 100% as it's the default but only of 10% and then let's also do in text of primary so again this orange color let's see how that looks like let's see this should reload and yes this looks quite nice in my opinion now under this actual tier name so this is our tier monthly um let's actually now also create the price thing so how much it costs a month so under this H3 element and under this diff element let me create another diff element let's give it a class name of margin top four Flex items which will be actually Baseline not Center then let's do a text which will be 6 XL and font which will be extra bold now inside of here I want to render the actual price so let's get dollar value then 30 so $30 and let's actually save it to see how it looks like this should now refresh and yes it looks quite nice but still I also want to say that at the end it's per month so monthly pricing so what I'll do right here is create a span element and right here let's do in slmo for month and let's also style that actually let's give it a margin left of one text which will be 2 XL font which will be medium and then let's also give it another text color to see in separation so let's do in text which will be muted of foreground let's save that let's see how that looks and yeah this looks quite nice let's see how it looks like in light mode and yes this also looks very very nice in my opinion now what else do I want I have have now the tier name the price I also want to have like a small tier description so under the stiff element let me create a p element and I will just now create some low ipom you can write whatever you want so let me do that real quick so I now just wrote uh write as many nodes as you want for $30 a month now this does not look good so let me also style that let's go in class name of actually margin top which will be five text which will be large and then also text muted or foreground to again have in separation let's see how that looks like and yes this looks quite nice let's see in dark mode and in dark mode it also looks quite nice now the next step which I want to do is actually create like an feature list so we will have like little bullet points of things which are included in the price of $30 a month so for that let's again go back and what I'll do now is go under this card content so under this card content component and we'll create a diff element let's give it a class name which will be Flex of One Flex Flex of call then justify which will be between let's get a padding X of six padding top of six and a padding bottom of eight let's do in PG of secondary rounded which will be large and let's also do an margin of one let's do in space y of six and then on small devices a padding of 10 and then also on small devices a padding top of six now inside of this sff element I want to now actually render a UL tag let's give it in class name the class name will just be space y of four and then inside of this UL I want to now render my feature list so what I'll do is actually create an array so on top right here let's do const I don't know um feature items this will be equal to an array with multiple objects so let's give it a name and the name will just be um I don't know lurm ipsm something and I will copy paste that 1 2 3 4 yeah I think this should be fine so I have that now five times and now inside of this UL I will actually map over this array so let's get our feature items right here let's do dot map and then we'll get an item and let's also actually get an index then let me return that and now inside of here I render An Li tag now you see we get an error right here from react and it tells me that I have to add in key prop so let's do in Key prop of index and let's also doing class name which will be flex and items of Center then inside of this Li let me render a diff element and now inside of here let's give it a class name of flex which will be shrink of zero then inside of this diff element let me render a check Circle so check Circle two I will use this one right here this is in self closing tag which is again also imported from Lucid react let's give it a class name which will be height of six W of six and let's also do in text green of 500 let's first of all see how that looks like so this should now load let's see and now you see 1 2 3 4 five check marks which looks quite nice now we also need to render the content so under this diff element but still in the LI let's now render a ptag and let's render our item. name let's save that let's see how it looks like um I think it does not look that good yeah as you see it does not look good so let's style that let me style the pag let's give it in class name of margin left three text of Base let's see how that looks like this should now look already way better and yeah I think it looks quite nice and I can live with that actually um now the last step has come and that's actually to create a button so like a submit button to uh buy it now or get it today something like that so what I'll do right now is go under this UL tag and then let's create a form element now I won't create an action for now so let me delete it then inside of this form element let me get the button component from sh and UI this is uppercased as always and then let's right here just say bye to today or something like that you can write whatever you want so let's see yeah it looks all right but I think the button should have the uh whole width so 100% so what I'll do right here for the form is give it a class name of w full and then also I will give the button a class name of w full let's see how that looks like it should now have the full width let's see and yes we now have the full width and this looks also very very nice so now we actually have created a pricing card and I think this time has now actually also come to make it actually work so if I click on the buy today button I also of course want to create a subscription in my stripe dashboard so what I think we should do right now is first of all set up stripe so let's head over to stripe so I'm now at stripe.com and this is what we'll use today to actually accept our payments so stripe is an actual payment processor so I already have an account so let me click on sign in and then right here inside of the dashboard let me click right here on the top right corner let me click on new account account since we of course have to create a new account and then let's just say Marshall SAS or let me spell it a bit nicer Marshall SAS I will leave the country in Germany that's fine it does not make a difference for you you can choose your country let me now continue so I will have authenticate so now I'm inside of the stripe dashboard and the first thing I want to actually get is the stripe um environment variables so if you click right here on developers and then click on API Keys you right here have your sec key and that's what I want so I will copy the secret key actually let me open my EnV file and I will just paste it right now right here we don't need it currently but I'll just leave it here then the next step which I want to do is Click right here in the Side Bar on more and then we should somewhere have right here the product catalog what I want to do right here is create a new product so let's add product then let me give it a name I will just say I don't know um Marshall SAS premium let me spell that correctly then I will do an reoccurring since this is on subscription and for the amount let's do 30 and not Euros but I will do dollars now this is monthly this looks good so let me click on ADD product this will now create a product in a stripe dashboard as you see so I can click on that now and that's what you now see we have an product which is $30 a month and we have right here an API ID which we'll need in a second so let me actually also copy this price ID and also paste it in our environment variables so that I don't have to go back right here so now we have actually set up stripe we have created a product and we got the API keys so now we can actually set up stripe and now to make stripe work we first of all need the stripe package so I will open the terminal right here let me stop my def server and let's do an mpmi of stripe just the normal stripe name this is stand the package which we'll use this package only works on the server and our whole stripe integration will be be completely server side in most videos which you will probably also have seen most people use stripe than swipe JS and swipe react so they use a combination of server site and client site but what I will do is actually do everything on the server and then we will call this whole um actual client side integration through the server so this is very nice we only need one package and also I think it's just a much cleaner approach than what other people do so to make strip work I will open my Explorer again let's go on the app folder then in the lip folder and let me create a new file which I'll name stripe. TS now inside the stripe. TS file all of our stripe code will live or actually everything which uh has to do with creating the checkout experience and the first thing we have to do is actually import stripe so let's do an import I will capitalize Stripe from stripe quite simple what I want to do now is actually also create a stripe client so what I will do is an export constant I will name it stripe this will be equal to new stripe and and now inside of here I have to pass our API key now if you can remember in my EnV or in my EnV file I right here already pasted my secret key so now let's create a new actual variable so let's do um stripe uncore secretor key and this will be now equal to this key right here so to our secret key which I've copied from our dashboard now I will copy this variable name so stripe secret key and let's go back to our file I can now write here just in process this will be lowercased so process. envy. theame stripe secret key let's also right here now actually um give it a bit of configuration so first of all the API version for the API version I will just choose the latest one right here and then also let's do typescript of true since I want to get the typescript benefits also right now we get an error it tells me argument of typ string or undefined is not assignable to typ string so all it all it says is it does not really know if this environment variable is defined or not so what I'll use in a quite simple fix as string and now I just tell stripe hey I know this is defined just leave it like that so now this is fixed this is very nice now under that what I want to do now is actually already create our function with which we'll actually then check out so let's do an export const we'll name it get stripe session and this will be equal to an async function actually so an async arrow function I haven't used them in uh quite some time but okay now inside of here I actually need a few params so I need the price ID which I've copied already in my environment variable right here I will need the domain so the current domain which we are on this will be Local Host in the development environment and then whatever our production uh uh domain will be and then at last the custom ID so that I can actually map the subscription to the actual customer in my stripe dashboard so let me actually right here just the structure it I want to get in price ID I want to get an domain URL and then I also want to get an customer um ID now right here types SCP complains a bit because it does not know what types these are so let me actually give it the types let me zoom in a bit for you guys so right here the price ID will actually be a string then we'll have a domain URL this will be also in string and then we'll also have a customer ID which also of course will be a string so now we got these params a price ID a domain Ur and a custom ID and now we can actually use them right here here so how do you do that is actually again quite simple right here we do a constant session this will be equal to AIT stripe so right here we have created our constant which is stripe and what we want to do right here is actually initiate a new stripe checkout session so let's use stripe. checkout. sessions. create and now we have to actually give it a few items right here so first of all our customer we'll give it the customer ID so that we now know hey this customer bought this so we can then also actually map it to the customer then the second thing is the mode so there are two modes actually or three modes as you see a payment mode a setup mode and a subscription mode and we of course need the subscription mode then the next thing I want to do is get the billing address collection I will just set it to Auto then the next thing we'll have the line items and what are the line items well white here I will just tell the checkout hey I want to check out this so right here in the checkout page I want to actually check out these items so this will be an array with an object then the price will be our price ID and then the quantity will just be one so this looks very nice then the next step which we'll have is the payment method types now you can actually set up multiple in your dashboard if you want to but we'll only accept one and this is card so Master card Visa card and whatever there is else now one more thing I want to do is the customer update field now what is that when well in checkout I want that the user is able to actually update the address and name for example maybe when the user created the account with our sass the name is not correct what I want to do is that inside of the checkout the customer can then update the name if he wants to so let's right here just do an address let's set that to Auto and then let's also get our name and let's set it also to Auto now we're almost done we only need two more fields and that's the success URL and the cancel URL so if the subscription is uh successful I want to redirect the user to an page where it just says hey your subscription was successful have fun something like that and if the subscription failed for some reason the user clicked out or something like that I want to get like a small screen that says hey don't worry you don't uh did not get charged if you want to you can try again so right here again let me just get the success URL now I will again use Optics let's get right here this custom value which will be a domain URL so right here we get through the perams the domain URL and then slash payment slash success this should be a double C and then let's also do the same for the cancel URL and for the cancel URL again Optics let's get the dynamic value of domain URL slash payment SL canell so this looks very nice we now have a success URL and a cancel URL and now the last step is to actually also return the session URL and this is then the URL where the user will get redirected for the checkout so so let's do in return session. URL as string so this looks very nice we now have actually created the function for which the user then gets redirected to check out to check out for our product so great this works very nice but now we have a problem right right here we passing stripe custom ID but if you can actually remember we never created a stripe customer so how do we actually fix that well what we have to do is actually when the user creates the account we have to create an swipe account for the user so how do we do that well we'll again go to our layout in the dashboard actually and then right here where we check if there's no user we'll now do another if check so under this if statement let's create another if statement so if there is no user do stripe customer ID let me write here doing constant data this will be equal to aate stripe stripe is now imported from the lip folder do customers not customer session I'm sorry but customer and let's you do create since I want to create a customer right here I will now just pass the email and the email will be equal to the email now we will create right here the customer in stripe but now I also of course have to actually pass the stripe customer ID to my database so what I'll do right here is an AR Prisma do user. update since I want to update the user and where we'll have to pass an ID which will be equal to the ID and let's also right here doing data so what exactly I want to update and I want to update the twipe custom ID and let's give it in value of data. ID let me save it right now and if I now refresh the page actually it does not work because my Dev server is not running so let's again do an npm1 Dev let's go back let me restart the def server again this now takes a bit so let me wait for that real quick so now you see my def serers again running I can again go to the homepage and now in Theory actually this tripe customer should be now created since I did this if check if there's no customer please create one so let's see I will now go to Stripe Right Here let me click on where are the customers and now we should have one customer and yes that's me so you see this fully works also we can see if this also is uh present in my database so let me open a new terminal Tab and let's do an npx Prisma in it or not in it I'm sorry but Studio since I want to open the studio and now you see right here in the studio I have now added a RP custom ID so this also fully works now and now we can actually create a checkout experience so that the user can check out since the user now actually has an swipe custom ID so let's actually do that so what I'll do right now is first of all I want to fetch data I want to fetch the user swipe customer ID so right here under this uh map or aray I'm sorry let's do an async function let's call it um get data and let me open that now inside of here I will create a constant data which will be equal to a Prisma now I will import Prisma manually again so let's do an import Prisma from our lip folder and now inside of here what I want to actually do is Select from a subscription model now as you see I don't have a subscription model if I open my schema. Prisma file right now we only have a user model but now I also want to create a subscription model so under this model user let's create a new model which will be called subscription I think this is spelled correctly let's see yeah it looks all right right let's give it right here stripee subscription ID this will be off typ string and let's you an at ID and at unique then the next field I want is the interval so what's the interval it will be monthly or yearly this will be of type string then I want to get a status this will be of string now what's the status well the status tells us hey is the subscription active is it cancelled is it pass do does the customer owe me money Etc then I want to get the plan ID this will be also of type string then let's get the current uh Period start this will be of type int so integer then let's get the current period um end this will be of type int and then let's also get the created at timestamp so this will be of type date time and at default of now let's also get the um updated at time stamp this will be of daytime and at updated at so now if you think about it we now have to create an relation between the user and the subscription model how do you do that you have in total actually three options one to one one to many or many too many now many to many does not work one to many does not work only one to one works because one subscription only has one user and one user only has one subscription so how do you actually do that in Prisma well it's actually not that hard as you would think so what I'll do now inside of the subscription model is right here get the user and this will be equal to the user and what I'll do is now just click save and in theory it should create the relation for me automatically so I will click save and the subscription model looks fine we get right here the user so right here we relate it to the user ID and then we've reference it here within string this looks actually quite all right let me actually also Mark it right here at unique since our user ID is unique but now the problem right here in the user model is that it gave us subscription array and subscription array actually means one too many but I don't want to have one to many but I want to have one to one so I will delete this array and add in question mark at the end and now we have created a one to one relationship now we of course also again have to push the schema to our remote database so I will stop my def server let me clear everything and let's do an npx Prisma DB push this will now push our code to our postgress database and it should work so let's see and yes as you see now our database is in sync with our Prisma schema this is very nice and you see this works so now I can go back to our page. ESX let me first of all restart my def server with npm1 Def and now right here I can now get the subscription model now what do I want to do inside of the subscription model well I want to find a unique subscription right here and then inside of here we actually now have to create a where statement so I only want to get a subscription where the user ID matches my current user ID so in the params let's just get the user ID this will be of typ string and then let's pass it right here so then what else do you want to select so let's create a select statement I want to select the current status so let's set that to true and then also from the user model I want to select actually the stripe custom ID so let's set that also to true so now we actually select the subscription status so if it's true if it's active or not and then also off the user descripe custom ID now I can actually return that data and now we can get it in the front end so right here I will do in constant data which will be equal to aate get data now you see we get an error right here so first of all aate expressions are only allowed within async functions so let's mark it as an export default async function and then also our get data function misses one argument which is the actual um user ID so if I go back to the Navar what we have to do is again import this get kind server session so I will copy the import actually let me paste it right here on the top and now I can use it in the component so let's do in const I will D structure this will be equal to get kind server session and what I want to get right here is the get user now let's do in constant user which will be equal to AIT get user and now we actually get the user ID so right here I can now just pass in as an argument the user. ID as string and now you see we don't get any errors anymore and this now also fully works so what do we do now actually well it's quite simple right here we now have this form with this spy today what I want to do now is actually make this button work and to make it work we have to create a server action so what I'll do right now is right here uh under this constant data let's create a new async function so let's do an async function uh which we'll call create subscription then let's open that now again the important thing is currently This Server action is just a normal client action so what we have to do is actually right here Market as you server to tell react hey this is in server action which should only run on the server now inside of here what I want to do is first of all if there's no actual so let's use the exclamation mark data. user. um stripe custom ID let's actually throw a new error so let's in throw new error and let's just say right here unable to get um customer ID something like that if there isn't so custom ID we can actually create the subscription so right here we can do in const um subscription URL this will be equal to AIT get stripe session now get stripe session is imported from our lip folder and from the stripe file actually and now inside of here we have to actually add a few things so the custom ID the domain URL and the price ID let's first of all add the custom ID this will be equal to data. user. strip custom ID then we also have to add a domain URL now the domain URL for now will be hardcoded and I would say HTTP um Colin sl/ localhost 3000 now at the end of course I won't make it hardcoded but for now it's actually fine and then the last field which we need is the price ID and the price ID I will actually get it right now from uh my environment variables if you open your EnV file right here we already pasted our price ID now let's actually also create a name or a variable name so let's do right here stripe uncore price ID and this will be equal to what I've just copied right here I will now paste it right here and now we have a strip price ID let me stop my def server right here let's clear it and let me restarted again since if we uh change environment variables the def environment has to always restart and I know next does that automatically but I'm just not the fan of it I don't know I just feel safer if I do it manually now okay we have now done that I can now actually do uh get it now right here so process. EnV do let's uh let me copy the name right here store price ID paste it and that's in as string so now in theory this should work the only thing I have to do right here is ADD also return redirect now redirect again importantly imported from next SL navigation and let me pass the subscription URL so now actually our server action should work now the last thing I have to do is actually set up the server action to work with our button right here so let's give our form a action for the action let's just say um create subscription because that's the name of our server action and before I actually test out if it works I want to actually make the button a bit better I want you again add the pending State and everything like that for that if you can remember we had this component called submit buttons where we actually created something like that so what I'll do right here is actually create a new export function I will name it stripe um subscription creation button I know very long name but I like this name and inside of here let me again get the pending State and now this will be equal to use form status again as always and now inside of here let's create a return statement I will use empty brackets and then inside of here I will now do interal statement so if pending is true let me return something and if this is false let me return something else so if pending is true I will just copy right here this button from the top since I don't want to change anything the only difference is instead of w fit let me do W full and then if it's not true so if the button is not pending I will just copy this button right here let me get it right here and paste it now the only thing that is currently missing right here is the type and the type will be submit now the only thing that I don't like right now is this by today name let me change it to um create subscription I think that's better and now we can actually use this component so now instead of this button let me render this tripe um create subscription button this is in self closing tag and let's see if this now works so I will go back to our def server let me reload our page this should load let's see so now our Dev server is running again let me now click on billing actually so we'll now get redirected to dashboard / billing and now we get an error cannot read properties of n reading user weird error right so let's actually try to understand what the error is um right here we have our aying function create subscription the error comes from this file and actually the error comes from here data. user. strip custom ID the error tells us that property of null cannot be read so we don't actually have an stripe custom ID where is that well right here we fetch our stripe custom ID based on a subscription which is currently not existent and that's why it throws an error and it tells us hey there's actually no ST custom ID I don't know what you want to do so what we actually have to do is fetch our stripe custom ID inside of the server action so right here what I'll do is a const DB user this will be equal to arrate Prisma now Prisma do user. find unique I want to find a unique user where the actual ID is equal to the user. ID then I want to select only one thing and that's the stripe customer ID so let's set that to true now right here instead of checking data. user what we want to do is if there's no DB user. stripe custom ID and then also right here instead of using data. user. stripe custom ID we'll use a DB user do stripe custom ID now you see we don't get any errors anymore and we can now actually use that so let me reload the page you now see we don't get any errors anymore and now I think it's time to test out if the subscription works so let me click right here on create subscription we should now get redirected to the strip page let's see you right here see we got redirected and now if I zoom in a bit for you guys you right here now see $30 per month I know for me it's currently in German but for you guys it should be in the local language but you see the price it's per month uh you can subscribe give your card details and then pay for it but before we try all of this actual stuff because currently it does not fully work as we need it because we haven't set up web hooks but we can test out something else if I click right here to go back so I will click right here to go back you'll see we'll get redirected back to our homepage but we get in 44 not found what's the error well we got redirected to/ payment SL canell and the problem is we currently haven't created a page for/ payment SL canell so let's actually do that so right now let me go to the code let me collapse everything let's go inside of the app folder and and then right here let me create a new folder called payment now inside of this payment folder we'll have two more folders so first of all the success folder and the canell folder let's start with the canell folder not file but folder and then inside of this cancelled folder let's create a page. TSX let me also create in the payment folder another folder this will be the success folder and let's create a page. TSX inside of here so let's start with the canell uh card right here or the cancel route let's start with an export default function this will be the I don't know cancelled uh route something like that let me open that and then inside of here let's start with a return statement so let's give it right here first of all a diff element let me give it a class name of w full let's do a minimum height of custom value 0 viewport height let me also do in flex and then items of Center and justify of Center to Center the children in the Center then let's use the card component imported from the components folder let me give it a class name of w custom value 350 pixels then inside of this card component let's render a diff element give it in class name of padding six then inside of this div let me render another diff and inside of this div I will now render a x icon so from Lucid react and this is a self closing tag let's see how that looks first of all so I will reload this page we currently get an error but this should go away and yes now we have this little card right here as you see now still this does not look perfect so let's actually change a few things so for the parent element of this x icon let's first of all style it let's give it a class name of w full flex and justify which will be Center and then for the X icon let's give a class name of W12 h of 12 rounded which will be full and then I want to have a BG of red which will be 500 and I want to have an opacity of 30% then let's do our text which will be ret of 500 and a padding of two let's see what it looks like this should look quite nice honestly and yes it already looks thousand times better now under this x icon and under the diff element let me create another diff element let's get in class name of margin top three text which will be Center SM so smaller devices and upwards will be a margin top of five and W of full inside of here I render an H3 tag and let's just say payment um failed let's save that and let's see how that looks and yeah it looks all right but we can of course make it look better so let's sty the H three let's get in class name this will be text of LG and then leading which will be six and let's also do a font which will be medium let's save that let's see how that looks like yeah it looks already way better that's nice now under the H3 let's render a diff element let's give it a class name of margin top 2 and inside of here let's render a pag and then for Content let's actually say um no worries uh you won't be charged I don't know please um try again something like that I think that's fine let's see how it looks like yeah it isn't looking that good but we can of course change that let's give it in class name of text which will be small and then also text which will be muted of foreground let your that looks like yeah already way better smaller and we also have a um color separation so now we have payment failed no worries so this description I think the last thing we need is some button with which we can then actually redirect to the homepage so under this pag and under the diff element let me render another diff element let's give it a class name of margin top five and on small device and upwards margin top of six and W of full now inside of here let me render the button component which is import Ed from our components now inside of here let me actually render a link component from next Das link let's say go back to dashboard let's also give it an HRA right here which will be the index page so just an empty slash let's see if this works let's go back and yeah this looks actually quite nice now there's still one thing I want to do right here let's give it a class name of w full so for the button and let's also do right in as child so if I now save that everything should still work and you see now we have the full width and now if I hover over it you see it links to our homepage so let's actually click on the button and we should get redirected to the homepage and that's exactly what happened so that's nice this also fully works now the second thing I want to do is create a success page so right here we have our success folder and what I'll do right now is let's go inside of this uh route Let's do an export default function this will be the success um route something like that and let me open that now let's create a return statement and for the return statement I will just copy the content in our canell route so since it will actually have the same look and I can now just paste it now we have to import the card component from our components now instead of an X icon so uh that did something bad let's actually import a check this is from Lucid react then instead of using the red color let's use a green color so also for the text green 500 that looks nice now for the text instead of payment failed let's say payment successful this looks nice and then let me import the button component from our components and then let me also import the link component from the next slash link so this should work let's see I will go to um actual slash payment SL suuccess Let's see we should now see a nice Cut component and yes this looks nice but now instead of no worries you won't be charged let's change that a bit so let me delete it and let's say congrats uh on your subscription um please check your email for fur uh further instructions something like that I think that's fine let's see what it looks like and yeah it looks quite nice so now I can click on go back to dashboard and we should get redirected and that's exactly what happened so this works perfectly now our cancelled and successful page both work so now let me click on building actually right here and what I'll do now is click on create subscription let's see if actually creating a subscription works so we got redirected this is nice right here for card data you can do 42 424242 this is just a demo card you won't be charged in uh real life no worries all is good we in a demo environment then for the month 4242 and for CVC 4242 for name I will say say J Marshall and Country looks fine now I will click on actual subscription or to subscribe to this plan this now loads as you see it was successful and we'll get redirected to Our Success page if I now go to stripe I can now click right here on payments and what you'll see right here succeeded $30 subscription created by customer so by myself I can also click on the customer tab right here on the customer itself so on me and you also see right here that I created a new subscription for $30 so congrats you have now created a fake payment I'm sorry this is not real life money but hey this is now already your first step into becoming a successful SS owner very nice right so now this has been created which is nice so I can now subscribe and everything works but if I now reload actually our page or not reload let me click right here and go back to dashboard and then let me click on building right here you will still see that I can again subscribe why does that show I am already subscribed I shouldn't be able to again subscribe well what we have to do is actually when we load the data right here we have to check hey does the customer have already in subscription if so what we'll have to do is show a customer portal where the user can change the subscription but before we even can do that we first of all have to actually set up an web hook so that our database knows that hey this user has created a new subscription so give him an status of active so the next step is actually to create first of all an web hook endpoint and after that we can actually right here show the customer portal Now to create our web hook I will go in the app folder in the API folder and then right here in the API folder let me create a new folder let's name it web hook I think that's fine and then let's also create a child folder we'll name it stripe and then in the stripe folder I will create a route. TS file now inside of this route .ts file we'll now actually create the API Handler or actually what we'll do is create in web hook with which we listen four events which will come from stripe so for example a user will create a subscription we will then take this event that stripe sends us and then update our database and based on the event so let's actually do that now this is actually not that complicated to create the only problem is that you have to actually write a lot of boiler plate but still we'll get through it now the first thing is that this won't be a get API route but in post API route since we of course want to post data to our database so let's do an export a sync function let's name it post uppercase and then inside of here let me get the request and the type will just be the request and let's open the function and now the first thing I want to get is the body element or the body I guess payload so let's do in constant body which will be equal to aate request. text and then the next step which I need is actually the strip sign signature so let's do a constant signature this will be equal to actually headers now headers is imported from next SL headers and we can actually get the headers since this API route won't be cached then let's do right here a DOT get and now inside of here I want to get the stripe Das signature now it's important it's very very important that you spell that correctly if you misspell it you'll get errors so please spell stripe signature correct if anything is if you're not sure if you spelled it correctly go to my GitHub and copy it from there just to be safe okay now I want to actually create um event so let's do let event and this will have a type which will be stripe let's import Stripe from stripe. event so now what we have to do is actually construct a web hook so the thing is currently we just check hey um do we get a body do we get the signature and what we do and what we have to do now is actually construct an event and right here we have now to pass the body the signature and then also a web hook secret and then we can construct an event so under this uh let event let's do a try catch statement so try and catch if there will be an error let's right here do an return new response also first of all right here for the catch let me also get the error actually and the error will be of type unknown and right here now return new response and let's just say I don't know web hook error now you could also paste the error right here if you want to but let me just pass a status and let's say 400 that's all I think that's fine now let's actually do the try statement so we can do right here the event and then this will be equal to stripe now stripe is imported from our lip folder right here so not anymore this uppercase stripe but the lowercase stripe and then let's Jo web Hooks and let's get do construct event since we want to construct a new event now we have to pass right here three things so first of all our body we have to pass our signature and we have now to pass our web hook secret now we won't pass it as in string you could do that but I won't uh recommend that what we'll do is restore it in the environment variable and then pass it right here so let me open my EnV file and then let's right here just do in stripe underscore web hook um Let me spell that correctly underscore secret and for now the value will just be some gibberish now let me copy the value right here stripe Rec poke secret and then inside of here we can do a process. env. strip webook secret as string now right here we currently get one error for Signature and it tells me argument of type string or null is not assignable to type string so what we'll do right here is just an S string and now we don't get any errors anymore as you see so now the next step is where we now actually create our strip web hook or we construct a new uh event what we want to do now is actually get the session so let's right to do a constant session and this will be equal to event. data doob and now let's also give this session a type so let's just do an as stripe. checkout. session so now we have an type and if you hover over session you see session is of type stripe checkout session this is very nice and now we can actually listen for our web hook events and then return whatever you want to return so let's actually do that right now so what we'll do is actually use an if El statement so under this constant session let's do an if statement and then let's do an event. type and if this is equal to let's say right here checkout um do session do completed so if the checkout has been completed we want to create a new subscription for the user the first thing I want to get is actually retrieve the subscription so let's write here a constant subscription this will be equal to await stripe do subscriptions and then I want to retrieve a subscription inside of here I have to now pass our session do subscription and then also Mark it as string now we don't get any errors anymore and this looks very nice now the next step I want to get is the custom ID or the stripe custom ID so let's do in constant um customer ID this will be equal to let's say string and then inside of here we can get the session. customer now the next step which I want to do is now fetch the user from our database so let's do right here constant user this will be equal to ARR Prisma now Prisma does not automatically import for me so on top I will do an import Prisma and let me import that from the lip folder and right here we can now continue do user. find unique since I want to find a unique user and now where the stripe custom ID is equal to the customer ID which we get right here from stripe so this is nice now let's actually see that uh the user actually exists so let's do an if statement and if there's no user let's throw a new error so let's throw new error and let's just say um user not found dot dot dot this looks nice okay so now we actually get the subscription we get the custom ID we fetch our uh user and if there's no user we throw error now the next step is to actually create an subscription for our user so let's do an aate Prisma do subscription do create since we want to create a new subscription and now we have to pass some data so let's start with with the stripe subscription ID and this will be equal to our subscription. ID quite simple right let's also pass our user ID not user but user ID right here and this will be equal to user. ID then the next step is to pass our current Period start now this will be equal to subscription. current Period start then let's also give it an C current period and and this will be equal to subscription. current period and right here then the next value is the status this is very important for us and this will be equal to subscription. status so it will tell us is the subscription active pass du is it currently trialing status so whatever it is currently and then let's also pass our plan ID this will be equal to subscription so let me get it subscription do items. data now data is currently an array so let's get the first value inside of here and let's do in plan. ID so now we get the plan ID and then the last step is to get the interval so how do we pay monthly yearly uh quarterly whatever and then this will be equal to string so we want to stringify it so right here then subscription do items. data we again want to get the first item in the way and then this will be the plan do interval so now we are actually done we have created the first event or we listen for the first event and that's the checkout session completed so again to um actually summarize what we did right here we check for this event right here so when the user has successfully checked out we then retrieve the actual subscription and then also the customer uh which created the subscription we fetch the user see if it actually exists if not we actually throw an error and then at last we create an actual subscription in our database so this is very cool but still we are not done we now have another event which I want to listen for so after this uh event type checkout session completed let's right here create another if statement and right here we'll check for if event. type is equal to invoice. payment. succeeded let's me open that now inside of here we actually have to do almost again the same we have to again retrieve our subscription so let's do in constant subscription this will be then equal to AIT stripe. subscriptions do retrieve and we have to now pass our current session do subscription so let's in session do subscription and then this will be as string to not get any errors so this looks nice and all we have to do now here is actually update the user subscription so let's right here do an array Prisma do subscription. update and then right here let's do anware statement since I only want to update a specific subscription and right here let's get the stripe subscription ID and this should be equal to the subscription. ID which we get right here from from our event then the next step we have to update some data and I want to update our plan ID this will be equal to subscription do items. data we'll get the first uh item inside of the array price. ID then the next step is to get the current period um start actually and this will be equal to subscription. current Period start let's also do the same for the end so let's get the current period end and this will be equal to subscription current period and then let's also get the status and this will be equal to subscription. status now that's actually all we have to do we have now done everything we need and we are now actually almost done with our response or with our web hook I'm sorry the last thing we have to do now is actually also create a new response so that our web Hook was successful so let's right here just do in return let me spell that correctly new um response and then let's do WR here null and let's give it an status of actually 200 and 200 just means hey this response was successful great everything works so we're now done we have created an actual web hook we have constructed an event and we check for two events now in production environments I would create way more events I would listen also for uh did the card get abundant should I do an aond card email I won't do it right now because there's a lot of events which you can listen for but these are the two most important one which you need to handle payments and that's why I will only Implement those two so now I think it's actually time to listen to this uh events so let me first of all go to the stripe website now right here in our stripe dashboard I will now click right here on developers and then click on web hooks now right here we can click on test in a local environment since that's exactly what we want to do I will authenticate right here and then once I'm actually authenticated what I want to do now is copy this twipe block in so that I can actually authenticate my CLI or my environment I will copy that now the important thing is that you have the CLI installed so the stripe CLI if you haven't just followed the guide right here I already installed it so that's fine for me I open a new terminal tab right here and then just paste stripe login it will now actually ask me to authenticate my project so I will follow the link and now it asks me hey do you want to Grant the strip CI access to your account information yes that's the correct um actual project so let me click on allow access it has now access or it has granted the access now if I now go back to our project actually you see everything was successful and we haven't got any errors which is great now the next step is to forward our events to our web hook so I will copy this right here and paste it right here now currently this is the incorrect URL so it isn't low Clos 4,242 it should be low Clos 3,000 and this shouldn't be/ web hook but it should be/ API SL web hook slst stripe now I can actually click right here enter and now it will actually get our secret key so now we have right here web hook secret key so I will copy this repb hook secret key since we need it and then in this environment variable I will now paste it right here for our EnV so now we have an actual stripe web hook secret and in theory our web hooks should now also actually work now one important thing is I want you to leave your web hook open right here in the second terminal tab it's very important that this tab is open because if not our whole web hook won't work now in our other terminal field I will just restart my def server just to be safe so let me do an npm 1 Def and let me go back to Locos 3000 so I'm now in loc Clos 3000 as you see and now let's actually test it out I will click right here on billing as you see and before I actually um actually check out right here let me go back to the dashboard let me close this uh web hook uh page let me go on payments and then right here I will just click on refund payment just uh to be safe let me click on refund this will take a bit and you see right here if I now reload this to page uh let's see you now right here see refunded okay and now right here I will click on create subscription to create a subscription you now see right here I can pay so let me click on pay now this loads we should get redirected in a second to Our Success page which we have created already so now you see this was successful we see we have a loading indicator I got redirected so if I now go back we should now open our terminal so the second terminal which I have right here and now you see everything which has been created I can now open another terminal field and now let's do an npx Prisma Studio to open our studio and see if we actually have a new subscription so the slads right here let's see we should now have our subscription model in a second so let me click right here on subscription we have one active subscription as you see and this is correct we should now also see the data and yes we have an interval of month a status which is active we have a plan ID a current Period start an end and when it was created Etc also you right here see its map to a user and that's actually myself I'm the user so you see here it actually works now let me click on go back to dashboard and what will we do now so our building page right here currently just has this pricing card let's actually now create the stripe customer portal so what we'll do right here is an if check and if the status of our subscription is active we'll render the customer portal and if not we'll render this pricing card so what we'll do right here is an if statement and if data. status is equal to active we will now return our um customer portal so let me return a diff element let me give it a class name of grid items which will be start and also gap which will be eight then inside of here I will create another diff element let me in class name of flex items which will be Center and then also justify which will be between and let me also do in padding X of two so on the horizontal side then inside of here let me do another div and let's say class name of grid and gap of one then inside of here I can render an H1 and let's just say subcription and let's also render a ptag and let's say settings regarding uh your subscription so let me actually save that and let's see how that looks like and I don't see anything uh well right here I don't return anything so let's do in return statement and I'll return that let me delete this column and we should now see our title and description in a second so let me just refresh the page and yes you now see a title subscription and settings regarding your subscription let's now actually style that so that it looks nice let's give it in class name right here of text which will be fre Xcel not two but fre XEL on medium devices a text of four Exel and I think this should be all let's see what it looks like and yeah it's now a bit uh bigger it looks nice let's also make our description look better let's give in class name of text which will be LG and then also text muted of foreground this should now have a grayish color and the text should be a bit smaller and yeah it looks way better let's see it in light mode and yes in light mode it also looks nice so let's now actually continue with creating actual button so under the P tag and then under the two following diffs so just above the last let's render a card component we have already imported that let me give it in class name of w full and LG of with 23s then inside of here let's get the card header imported from our components and let's get a card title then right here we'll say um edit subscription let's also render under the card title a card description and right here we'll just say I don't know click on the button below um this will give you the opportunity to change your payment details and view you um your statement at the same time something like that write whatever you want I think it's also not written correct right here but I don't care let's see what it looks like we should now have a card with an title and a description and yes that's exactly what you see right here it looks quite nice now under that I I want to now render the actual button so under the card header let me get the card content and then inside of here I'll just render a form now let me just delete the action for now since I don't have any and inside of here I will just say a button currently and let's just say I don't know uh launch something launch uh portal we'll change it I will I just want to see the button and let's see it loads it loads and yes you see launch portal it looks quite nice now before I create the actual action I think we should actually first of all style our button and to do that let's go to our component which is called submit buttons. TSX and we'll create a new function so let's do an export function let's name it um stripe portal and let me open that function inside of here let me again get the pending state so I will just copy paste it and then let's create a return statement let's use these empty brackets right here let's do and check so if pending is true let's use the Turner let's return something and if this is false let let's return something else so if the button is currently in a pending State let me just copy this button from here from the top let's paste it um instead of w full lets you in W fit and then for if it's not true so if the button is currently not in a pending State let's again get our button so button component and let's just say view payment uh details I think that's fine let's also give it a class name the class name will be W or full or not full I'm sorry but fit and let's also give it in type of submit so let's save that and let's go back to our building page and now instead of rendering this button let's actually render our component which is the stripe portal component so now this should actually work so let me save that let's see how it looks like so this should now change and yes we now have the button view payment details and that looks quite nice but if I click on it you see nothing currently happens and that's because our form is currently not set up to anything and we just default to a get request so let's first of all create a new server action we have first of all this server action currently right here which is the create subscription uh server action underneath that let's create a new Asing function and let's name it create customer portal and let me open that function let's first of all mark it as use server since I want to tell react or also next shes hey this is in server action which should run only on the server now inside of here let's do a constant session this this will be equal to aate stripe we import Stripe from our lip folder billing portal. sessions. create since we want to create a new portal now inside of here we have to actually um return a few things we have to get our customer or our custom ID so let's say data. user. stripe customer ID and then I also have to pass a return URL so where we should return after this actual um customer portal so let's right here just say HT ptpm sl/ localhost 3000 SL dasboard now you see we currently get an error right here and it tells me um customer type string null or undefined is not assignable to type string so let me do an ass string and now we don't get any errors anymore now the last thing we have to do is actually also redirect the user to the customer portal so let's right here doing return redirect and then let's pass the session. URL now this should actually work so let's actually now hook up our server action to our form so let's give it an action and now how did we name it well we named it create customer portal so I will copy the name and paste it right here so let's actually test it out right so I will go back I will reload a page again just to be safe and what we'll do now is actually click right here on view payment details and now we got an error you can't create a portal session in test mode until you save your customer's portal settings in test mode so I will copy this here L now importantly don't copy the dot at the end or you'll get an error and let me just paste it right now inside of our dashboard so now we get redirected as you see and what I have to do now here is just click on Save changes with that I now actually allow the customer portal and if we now actually go back I will just refresh the page right here so that we don't see the error anymore and now I can actually click on view payment details you see we have a loading indicator right here and we get redirected to the stripe um actual customer portal as you see right here and now you see also the active subscriptions I currently have two but we already refunded one so that's all fine so this is quite nice as you see and if I now click right here on the top to go back to my actual website we should get redirected just to our normal dashboard and that's exactly what happened and as you see this is perfect since this now fully works as we wanted it to so now I think the last step has come and that's actually to make our homepage work so currently we don't have anything it just says hello from the dashboard and I think we should actually change that now before we can actually do anything I think we should actually first of all create a new model in our schema now this will be the model node so let's do a model which will be called node and let's open that now what's the first thing we have to add well that's the ID this will be of typ string at ID at default and this will be just uu ID then the next value which I want to have is the title this will be of type string let's also do a description this will be also of typ string let's do a created at timestamp this will be of daytime at default now and let's also do an updated at timestamp and this will be of type daytime and let's do an at updated at then the last thing I want to do is create a relation between the user and a note so how do we do that well again there are three relation models one to one uh one to many and many to many now I want to create a one to many relationship so one note can have one user but the one user can have multiple notes so how do we do that well it's actually very very simple right here in the user model we'll just say hey I want to get the notes and this will be equal to note with an array symbol if I now click save you'll see everything will be generated automatically now again if you want that it actually also generates automatically for you you can go to the extensions stab and install the stripe extension so I will search for it and not the stripe I'm sorry I'm in Prisma not in stripe so let's search for the Prisma extension and that's right here so if you install it you will get the same actual Auto generation so we're now done we have now created the node model and we also have a relation to the user model I can now actually open the terminal let me stop everything clear everything and let's do an npx Prisma DB push to push our schema to our actual remote database at super base so now you see our database is now in sync with our Prisma schema in and this is very nice let me reload our def server of npm1 Def let me restart it right here and now let's actually create the page so what I'll do right now is go inside of the page. TSX in our dashboard so page. TSX in the dashboard right here where we say hello from the dashboard so now let's actually change that let me first of all delete everything inside of this return statement and let's create a new diff element let's give it in class name this will be of grid and items which will be start and then also Gap y of eight then inside of here let me create another diff let me give a class name which will be Flex items which will be Center justify which will be between and then padding X of two then inside of here I create another diff element let me say class name of grid and gap which will be one and then inside of here I render an H1 inside of here let's just say your notes and under that let's render a pag and let's say here um you can see and create new notes something like that let's see how that looks like so this should Now update and yes as you see your notes and our small description let's now style that so for our H1 let's get an class name of text which will be fre XL and on medium devices a text of 4 XL for the description so for the pte let's do class name of text which will be LG and then also a text which will be muted of foreground let's save that let's see how that looks like this should look quite nice and yes it looks very nice now under that or actually on the right side so what I want to do is right here on the right side a button where the user can click to create a new note actually so under the pag and under this div element I will now actually import our button component from our components let me go to ITN property which is as child and inside of here let me render the link component imported from next SL link and let's say create a new note let's also right here give it an h and H will just be slash dashboard SL new let's save that let's see how that looks like so right here on the right side we should now get a button and that's exactly what you see create a new note this looks very nice in my opinion and we have now created The Heading now what will we do here well right here on the bottom I of course want to render the noes but what happens if we don't have any noes we have to have something like in default state if the user does not have any notes created so what I'll do is actually fetch the data and we'll do an if out statement and if we have some data we will show it right here and if not we'll just show a default um I don't know you don't have any notes create a note so let's go back to our code and then on top right here let's do an async function let's do get data and then right here let's uh open that then inside of here let's do in constant data which will be equal to aate Prisma now Prisma does not automatically import for me so on top Let's do an import Prisma from our lip folder then right here we can continue with array Prisma do note. find many since I want to find many notes and I want to find them where our user ID actually matches our current user so in the params let's get the user ID which will be of type string now we can pass it right here and now we don't get any errors anymore now also another thing I want to do is do an order buy since I don't want to just order with some random thing but I want to order by the created at timestamp and I want to get the actual newest items or newest notes on the top and then the oldest at the bottom so let's you create it at descending so descending means the newest ones on the top and the oldest ones at the bottom now the last step is to return the data so let me just do right here and return data now let's get the data in our front end so let's in constant data equals to A get data we now get an error right here it tells me array expressions are only allowed with an async functions so let's do an export default async function now we have one error less now the second error is expected one argument but got zero so we have to pass the user ID now how do we get it well in our Navar we already done that we import get kind server session and then just get our user so let me copy this import statement right here let me go on top and again paste it and now right here we can do a con let me the structure and this will be equal to get kind server session and I want to get the actual get user function now let's do in constant user which will be equal to aate get user and now we can pass it right here as an argument so user. ID as string now we don't get any errors anymore and this looks quite nice so what we'll do now is under this button component and under the diff so just above the last div let me now do an a turn so if data do length is smaller than one so if it's zero in that case let's use anary let's return something and and if this is false let's return something else right here let's just say if just to not get any errors anymore and now on the top right here so if we don't have any items let me return another diff element let's give it in class name this will be Flex let's do a minimum height which will be in custom value of 400 pixels then let's also do a flex which will be call items which will be Center let's do justify which will be Center so that we uh actually Center all of our children then let's you round it which will be media and a border a border which is dashed since I want you have like little dots let's do a padding which will be eight Let's do an text which will be Center and then let's also do animate which is in and let's do an fade in of 50 now inside of this diff element let me render another diff element and then inside of this diff element let me render a new icon which is the file icon I import that from Lucid react let me also give it in class name which is W of 10 and H of 10 let's also to do a text which is primary let's see how it looks like I will save that and I will go back and that's what you see right here we have a card element and then also this file icon now this looks not that nice so let me actually style the parent um diff element let's go and class name of flex uh age of 20 width of 20 items which are Center justify which is Center and then let's also do a rounded of full and BG of primary and I want to get 10% % of the opacity so I will do an BG primary of sl10 let's see how that looks like this should look quite nice and yes it looks very very good in my opinion now currently you see we don't have any padding at the top and that's because I misspelled right here Gap Y8 so let me add in dash and if I now go back we should now see a margin to the top and yes that's exactly what you see so now we can actually create right here an H one so en title and a small description so under the file icon and under the diff element let me me create a H1 and let's just say you uh you don't have any notes uh created let's save that let's see how that looks like and yeah it looks all right but we can style it a bit better so let's actually right here give them class name this will be margin top of six since I want to have a bit of margin to the top let's do in text which will be Excel and then font which will be semi bolt let me also create a description under the H2 and now for the content of the pag I will just paste something and this is right here just you currently don't have any notes please create some so that you can see them right here let me save that let's see how it looks like it should look not that nice but hey so yeah you see it does not look that good so let's give it a class name right here for the pag a class name of margin bottom which will be eight let's do margin top of two let's do text which will be Center a text which will be small then let's also do a leading which will be six and then also a text which will be muted or foreground now if you save it you you see it looks currently like that one thing I could maybe use also Max width so let's do Max width of I don't know SM and then also MX of Auto let's see how that looks like and yes I think this looks even better now the last thing I want to do is render a button at the bottom so it says something like create new note so under this P tag right here let me render a new button component and let's right here just copy it right here on the top actually so that I don't have to write everything again let's see how that looks like so here we now should have this button and yes it looks quite nice in my opinion as you see so now we're done with the default State when the user does not have any notes and now we should actually also make the ability so that the user can create a new note so let me go right here inside of our Explorer in the app folder inside of the dashboard folder and let me create a new folder called new then inside of here let's render a page. TSX now this route will be actually there to create new noes so let's do an X export default function this will just be called I don't know new node route and then let me just open that function inside of here let me create a new return statement and let's return a card component this is imported from our components and then inside of here I will render a form element now for the action I will leave it empty for now since we don't have any action currently let's now render a card header this is imported from the components then inside of this card header let me render a card title and then inside of this card title let's just say new note then under this card title let me render a card description imported from our components and let's just say right here you can now create your new notes something like that I think that's fine we can actually save that and see how that looks like so let me click right here on create a new note and now you see how it currently looks like so we have right here now new note and right here you can create your new notes so looks quite nice but still not perfect we now have to actually make space so that the user can actually create a new note so under the card header I will now import the card content again from our components let me give it in class name which will be Flex Flex of call and then Gap y of actually five now inside of here let me render a diff element let's give it a class name which will be Gap y of two flex and then also Flex of call now inside of this diff element I render a label component component so from our components and let's just say title then under this label let's now render a input component also imported from our components this is in self closing tag and inside of you let me give it in required field let's also do in type which will be text let's also give it a a name so the name will just be title and let's also give it a placeholder and the placeholder will be title for your note so let's save that let's see how that looks like and yes you now see the title and then also our input right here let me now also create our actual text area so under this diff element let me create a new diff element let's give it a class name and this will be Flex Flex of call and then Gap y of two inside of here I will now render a label component as always and let's just say right here description now under this label I want to render a text area and I don't think we have that currently installed and no we don't so let's again go to you i. chat.com and what I want to do is install the text area component since we want to write our description right here so let me copy the installation Command right here we'll use npm let me open a new terminal Tab and then I will just paste it right here so now we installed the um text area and now I can use it right here so let me get a text area from our components this is again in self closing tag let me give it a name this will just be lowercase description and and let me also go in placeholder this will be describe your note as you want something like that and let's also do in required field let's see how it looks like I saved it and yes it looks quite nice so we now have an title input and a description input let's see how it looks like in light mode and yes it also looks very nice now the last two things I need are two buttons so one button to go back and one button to save so under this card content I will now create actually a card footer this is again imported from our components now for this card footer let me go the class name which will be flex and justify between because I want to have these two buttons um actually spaced between each other then inside of this card footer let me render a button now this button is imported from our components let's right here um get a link so from next SL link we'll import the link component and let's just say cancel then let's also give it an H since that's of course very important and the H will just be slash dashboard let's save that let's see first of all how that looks and we should now see on the bottom corner right here a cancel button now one thing I forgot right here for the button let me give it an also an S child element and this should now actually look better so yeah cancel and everything still works now the last thing we need is our submit button and now I don't have to actually create a new submit button because if you go to our submit buttons component we already have one right here on the top a submit button and this is exactly what I need so right here I can now just import our submit button and then this is a self closing tag we can now save that and now you should see right here two buttons one cancel button and one save Now button now what I want to change is currently that they both have the same color so for the cancel button let me actually give it a variant and this will be actually just I don't know let's do secondary or we could do destructive let's do destructive this should now get this red color so that it shows like a danger and yeah I think that looks quite nice we now have a color separation now I think we should now actually make it work so that the user can actually create a new note because this currently does not work but before we do that let's check out if the cancel button works so I will click on that and we should get redirected to the dashboard and yes this fully works let me click again on this button and we get redirected to create a new note so let's make now our server action work to create a new note so right here Above This return statement but still in our function Let's do an async uh function let's just name it post data let me right here get the form data this will be of type form data and let me open that function now currently this is just a normal client acing function so let's mark it as use server so that react knows hey this is in server action and then inside of here I have to get two things I have to get a title and I have to get a description how do we do that now if you have a good mind and you can remember you should know that we just use form data so I can do WR here constant title and this will be equal to form data and now I want to get something and what do I want to get well I want to get the value of this input this input has a name of title so I can copy it and paste it right here let's also Mark it as string actually then under that I also want to get the description so let's do constant description and this will be equal to form data doget and I want you get the descript deson and we gave it a name of description so let me copy that paste it right here and Mark it as string this looks quite nice what we can do now is actually also post our data to the database so let's do an arrate Prisma now Prisma does not import for me so on top Let's do an import Prisma let me spell that correctly from our lip folder and let's do an array Prisma do note. create since we want to create a new note we now have to pass some data actually in total three values we have to pass a user ID this is in string we have to pass a description which is also in string and we have to pass in title which is also a string so we almost have already all Fields so for the description we can get the description right here then for the title we can also already get it right here since we get it through the form data and the only thing missing is the user ID how do we get the user ID well we again use this nice handy function provided by kind so I will go again to the Navar to actually copy the import statement so right here import get kind server session then on top I will just import that or I'll again paste the import statement and then right here just above our asnc function post data let's do in constant let's the structured this will be equal to get kind server session and now I want to get the get user function now right here let's do in constant user and this will be equal to await get user now currently you see we get an error and it tells tells me AWA expressions are only allowed within async functions so let's do an export default async function now we don't get any error anymore and we can now pass right here our user. ID now one thing I also want to do right here just above where we get our form data let's an if statement and if there's uh no user let's throw a new error so let's throw new error and let's just say uh not authorized let's save that so now I think this should actually work and then the last thing I want to do actually when the user or when actually the server action is finished I want to R redirect the user again back to the dashboard so what you'll do right here is and return redirect let's return and then the redirect is uh function is imported from next SL navigation and we want to redirect to um/ dashboard so I will save that and now I think it should work the only thing is that we have to actually also give our form the action of post data so for our form let's give it an action and this will be post data so now let's save that and let's see if that works I will do in hard refresh again just to be save and then right here let's just say for the title new note and then for the description let's just say hey how are you let me now click on Save now we see imp pending State we should now get redirected to the dashboard route so it still loads let's see and now you see we got redirected to/ dashboard but now we don't see this default template anymore where we say hey please create a new note but now we just see nothing so what we have to do now is actually render our notes in our dashboard index page so let's first of all do that now to do that let me again delete this div element let's create a new diff element let's give it in class name which will be Flex Flex of call and then a gap y of four inside of here I want to Now map over my data so let's get data do map and then get our item so let me now return that and inside of here I want to now render a card component imported from our components let me first of all give it also a key right here because you see currently react actually complains a bit and it tells me missing key prop for element iterator this is just for hydration so let's do key which will be item. ID let me also give it in class name and the class name will be Flex items which will be Center and then let's do in justify which will be between and then also padding which will be for then inside of this card ARA Renda diff element and then inside of this diff element I'll render an H2 and then this H2 will just have our item. title and let me save that and let's see how that looks like so now you see this one small card with our new note which is the title of this note so let's style the H1 actually or the H2 let's give it in class name which will be font of semi bolt let's do in text which will be XL and then also text which will be primary let me save that let's see what it looks like and yes this looks quite nice now let's also render right here the date when our note has been created and then also on the right side a button to delete the new note and added also the note so under the H2 let me render a p element and then right here we'll just do a new uh in NL so I think that's International I'm not even sure date time format now what local do we want to use we want to use en- uppercase us and now I can also add a few more things that's the dates Style I want to have the full date style and then right here at the end let me just do in dot format and this will be a new date and we have to pass our item. created at so if I now save that let's go back and yes this looks quite nice and I don't think we have to even change anything so now what I want to do is right here on the right side the two buttons which I already told you about so the delete button and then also the edit button so what we'll do right now is go under the pag and under this div element so just above the card component let me render a new div element let's give it a class name and this will be flex and GAP X of four then inside of here let me render a new link component and I have to of course give it an H the H will right here be upper tick and then let's say slash dashboard slash um new and let's use right here in Dynamic value of item. ID now why exactly did I choose this um I guess URL so/ dasboard SL new this is the route where we create a new um note and then SL item id this will be our unique identifier with which I can then later on added our note now inside of this link component let's render a button component and now for the button let me first of all give it in variant the variant will be outline and let me also give it in size and the size will be icon then inside of this button let me render our edit icon from Lucid react and then inside of here let me get a class name of W4 and H of four let me save that and now let's see how that looks so yeah as you see this button looks quite nice now the next button is this delete button so under this link component let me now render a form element let me delete the action for now since I don't have any and then right here let me render a button component and for the button let me just get a trash icon so from Lucid react and then let me give it in class name and the class name will be uh height four and width of four also for the button let me give it in variant and the variant should be actually destructive and let's also give it in size and the size will be off icon let me save that let's see how it looks like so on the right side we should now have an red icon with an trash icon and yes that's exactly what you see you have a red button with a trash icon inside of it so this looks quite nice in my opinion let's see it in dark mode and yes in dark mode it also looks very nice but if I now click on this edit icon right here we'll get redirected to to/ dasboard SL new sln ID but we get an 44 not found why do we get an four4 not found well that's because we currently don't have the route which would work for this Dynamic slug so let's actually create one to create one what I'll do know is open our Explorer go in the app folder in the dashboard folder in the new folder and then let's create a new folder with these brackets and say ID now what are these uh brackets actually so if I use these brackets in an next shest context I tell next shares hey this uh route should be in Dynamic route and then with this ID name I can get it then through the params so this ID can be anything so as we see right here this ID or just some gibberish but later on I can then just get this um jush through the params so through the params do ID name now inside of here inside of this folder let me create a new page. TSX and let's do an export um default function let's say d Dynamic route and let me just return that right here now inside of here let me create a return statement now for the return statement I won't write the code again right here for/ new route it will be actually the same code so let me just copy that let's uh paste it right here the only thing we have to do is now import everything so let me import the card from our components let me import the card header from our components let me import the card title from the components the same for the description from our components let's import the label from our components let's import the input from our components then let's get the card content also from our components then also the text area of course let's get the card footer let's also get the button right here let's get the submit button and then let's also get uh get the link component from next /link let me also delete this action right here since we currently don't have an action let me now save that and now we shouldn't get any error anymore so I will refresh the page and now we should see in a second that everything still looks nice and yes this looks nice but let's change it instead of new note let's say edit note so right here let's just say edit note and then for the card description let's just say right here right here you can now edit your um note I think that's actually fine let me now save that and let's see yes we have now a title edit note and right here you can now edit your notes this looks nice but now I actually also want to fetch the data so that I can propagate it right here for the title and the description for that right here above our export default function Let's do an async function which will be get data and then let me open that now inside of here let's do a constant data which will be equal to a Prisma now Prisma does not import for me so on top Let's do an import um Prisma from our lip folder and right here we can now do an a Prisma do note. find unique since I I want to find a unique note now we have to add an wear statement and now inside of this wear statement I actually have to check two things so first of all the ID of the node has to be the same and then also the user ID has to be corresponding to the current user so what we'll do right here in the params let me destructure the user ID and then let me also get the node ID now let's give it also in type since currently typescript complaints so the user ID will be of typ string and then the note ID will be or soft type string so now we don't get any errors anymore and now instead of using these empty strings for the ID I can give it a note ID and then for the user ID I can give it the user ID now let me also select a few things so let's create an select statement and then let's select the title so let's set it to True let me also get the description let's set that to true and let me get the ID and let's set that also to true now the last thing is what we have to do is return the data and now let's get it in the front end so let's in constant data which will be equal to arrate get data and now we get two errors the first one is ARR expressions are only allowed with an async functions so let's mark it as async and then also right here for get data we have to pass our user ID and the note ID let's first of all pass the um user ID so in the Navar I will just copy again this import statement to get our client server session let me paste the import statement right here and then above con data let's just do a const let me the struct this will be equal to get kind server session and I want to get the user right here then let's also do a constant user which will be equal to aate get user and now I can pass our user ID right here so right here I will have our user ID and this will be equal to user. ID as string now the next thing I have to pass is the note ID and I already told you I'll get it through the params so right here I can now D structure our params and we also have to give a type and the type will be params which will be equal right here to ID which is string so now we know params has an ID and the ID string so right here I can now just get our note ID and this will be equal to perams do ID now you see we don't get any errors anymore and this now fully works so what I can do now for our title is give it in default value and the default value will be a data. title let's do the same also for the description or the text area and let's say default value and this will be a data. description let me actually save that let's go back and now we should see in title and a description and now that's exactly what you see U see new note and then also hey how are you so this fully works now and now I think the second step is actually to make it work that we can save our edits because currently this button does not work let me first of all see if I click uh if I click on cancel do I get redirected and let's see yes I got redirected again to my note let me again click on edit and hey this fully works so now let's actually make our server action work let's do an async function this will be called post data and then let me open that right here in the params let me get the um form data this will be equal to form data or the type will be form data and then inside of here let me Mark it as use server since this is of course a server Action Now inside of here let's first of all do an if check if there is um no user let's just throw a new error and let's just say you are not allowed something like that whatever you want then inside of here we of course now want to get the title and the description how do we do that well we get it through the form data so let's do constant title this will be equal to form data. getet and I want to get right here the value from this input and the input has the name of title so I will copy that and paste it and let you ask string I want to also get a the description so let's do constant description and this will be equal to form data. getet and I want to get a text area with the name of description I will copy that paste that and let's as string now the last step is just to update our note so let's in AIT Prisma do note. update since I want to only update one note now inside of here I have to give it Anwar statement and I want to edit the note where the ID is equal to our data. ID and also where the user user ID is equivalent to the user. ID now let's update also some data and right here I want to update the description this will be equal to our description and then also the title which will be also equal to our title so now this should actually in theory work let's give our form actually first of all an action also which will be post data and before I actually test it out one thing I also want to do is when our server action is done I want to redirect the user again back to the dashboard so let's let's right here doing return redirect redirect is imported from next SL navigation and let's just redirect to/ dasboard let me now see if this works I will do in hard refresh to be safe and now let's edit our title from new note to Old note I know very very original now let me click on Save now we have in pending State and we should now get redirected to our dashboard so let's wait for that and as you see I got redirected to our dashboard and now we have an old note right here but currently you see it got updated to this title old node but in a production environment this would not fully work because we actually have in cash so what I'll do uh after this array Prisma I will do an revalidate path since I want to actually revalidate our data after that has been created so let's use slash dashboard just to be safe in the production environment so now you see it works I can click again on the edit icon right here I will get redirected let me again change it to new note let me click on Save now this will now again save and should again redirect us to our dashboard and yes we got redirected and we have now again the new title of new note so this now fully works and the last step is to actually make also deleting work so let's make that also work for that let me scroll down again right here in the dashboard page and right here we have an form as you can remember let me first of all give the button right now A type which will be submit and now we have to create a server action so that we can actually delete delete the note so on top let me create a new server action right here so just above the return statement I will do an async function let's call it delete note and then inside of here let me get the form data this will be of type form data and let me open that function now inside of here let's mark it as use server as we always do but now we have a problem right we want to delete one specific note and to delete a specific note I have to get the ID now you might ask ask yourself how do you do that it isn't that easy because our data is an array and I don't have the ID well we'll now go back to the old PHP times and we'll create an input type hidden so right above the button right here I will create an input which will be of type hidden I will give it a name which will be note ID and I will give it also value of item. ID so now we have right here the note ID and if I copy the name now what I can do is get it through the form data so I can do a const note ID and this will be equal to actually form data. getet and I want to get our node ID let me also Mark it as string and now we get the actual ID of the current uh note which I want to delete now let's right here do arate Prisma do node. delete and I only have to pass now one thing and that's the where so which note do I want to delete and I want to delete a note where the ID is equal to the note ID let's now actually test it out so I will copy the name of the delete note let's give it our form so let's give it an action of delete note and in theory this should now work I will now refresh our page again just to be safe and now let me click on this delete button so in theory everything should now be deleted but now the weird thing is even though I clicked on the button to delete our note our note is still here well why is that because if I know refresh our page so I do an hard refresh you will see that our note isn't there anymore and yeah the note is not anymore but why was the note still there when I clicked on delete well that's just an cash thing with next shes you have to revalidate your cache to see an update so after we done this a Prisma note. delete we can use right here in function which is called R validate path imported from next slash and now we have to pass the URL which I want to revalidate and I want to revalidate the/ dashboard route so let me save that and we can try it again so let me click on create new note since we will create a new note let's just say right here new note and let's say hey how are you let me click on Save now we now have in pending State I should now get redirected to/ dashboard that's exactly what happened you now see this note right here and our trash icon I will now click on this icon and now our note should get deleted and we also should see in revalidation of the cache so that the note goes away and that's exactly what happened our note is not there anymore and everything has been done automatically without me hard refreshing isn't that nice let's test out everything again I will click on create new note let's say hey new note let's say hey how are you let me click on Save now we have now in pending State as always then we should get redirected to/ dashboard now we in/ dashboard I can click on this edit icon now so you'll get redirected to/ new SL to the ID I can now change it from hey new note to hey hey old note let's also change a bit of the description and now let me click on Save now this will now again have an pending State and we should again get actually uh redirected to/ dashboard and now you see this works let me now click on the delete button and now this should also delete for us now one thing we could maybe do is add a delete State for the delete button or a pending state I'm sorry let me create a new note first of all let me add some description let's click on Save now and let's actually ALS so now create this pending state for this trash icon so where do we have it that's right here so let's again go to our submit functions uh file and we'll create a new function right here let's do an export function let's name it um trash delete and let me open that inside of here let me get this pending state so I will copy that and paste that and then inside of here let's in return statement so let's use these empty brackets and let's use again inary so if this is true so if pending is true let's return something and if this is false let's return something else if this is currently not true so the button is not pending let me just copy the button from here and I will just paste it down below and if this is true I will also uh paste it right here let me import the trash icon for B from Lucid react and one thing I want to change is if we are pending I don't want to render in trash icon but I want to render the loader to Icon and for the class name I will leave everything the same I'll just add an animate of spin now we can save that I will copy the name and then instead of rending the button right here let me render our trash delete function I will import that from our components let's save that one thing I will change right here is instead of type submit so when pending let's add a disabled State and I think this should now work so let's go back we got now actually redirected to/ dashboard and now let me click on the trash icon you now see the spending state that we are current currently deleting and then we should actually get revalidated so the cash and as you see we don't have a note anymore does that not look beautiful I think it works great honestly I think we are now done I'm now again on our index page so our marketing site and I just want to test out if everything works so I will again click on sign in right here this will now redirect me to the dashboard page and now I'm in/ dashboard let's see if everything works let's start with the settings page right here you see see now I'll get redirected to/ settings let me for example change my name to just Jan and let's change our color scheme to Green so right here we have green and let me click on Save now so this should now actually R validate our cache and then our theme should change so you see that's happened now let me click on billing right here we should now see the customer portal and that's exactly what I see let me click on view payment details I should now get redirected to stripe and that's also exactly what happened as you see right here let me again click right here to get back to our dashboard so to our actual website and now let's actually create a new note so let me click on create new note I will now get redirected to dashboard SL new let's write here for a title say hello this is very cool and for description some jush because why not let me now click on Save now we have now a pending State and we should again get redirected to/ dashboard and that's exactly what happened I can again click right here to edit our note let me just change the title to hello this is a very cool thing and let me click on Save now it will again revalidate the cache and then redirect me to/ dashboard so now you see we got redirected and we see our note right here let me click on delete and it should now also actually work and yes as you see our note got deleted and practically actually everything works and now we have only one more problem before we can actually go and deploy our application and the problem is that actually currently every user even though when the user is not subscribed to our billing plan or to your subscription can actually create a note we don't want to do that so what will we do well let's go inside of dashboard SL page so inside of our dashboard index page and what I'll do right here is actually just check if the user has an active um subscription if the user does not have an active subscription we will redirect the user to our bilding page and if the user has an active subscription we'll just leave the user where he is so now to actually get the current subscription status of the user what I'll do is actually write my my query right here a bit different let me first of all comment it out for now and let's right here do a constant data this will be equal to aate Prisma do user. find unique I want to find a unique user where the user ID so right here the ID will be equal to the user ID now right here I want to actually select a few things so first of all I want to get the notes so let's set that to true and I also want to get a subscription and from here I will now actually select our um status this is all I need so I only need the notes and I need my um subscription status and now I can return this data now you see we get a bit of an error right here so data. length does not exist we want to get now the data do um noes actually and now we get another error and data. noes. length is possibly undefined so how do we fix that well actually instead of checking for is it smaller than one let's just do if it's equal to zero then this error is gone and then right here we also have to doing data. noes. map now you see we right here don't get any errors anymore and if I would save that and go back and just reload the data again or our death server in that sense you would still see that everything works as it worked before but what I want to do now right here for this button where we actually link the user to create a new note I want to check if the user has an active subscription so let's use intern right here so if data do subscription. status is actually uh equal too active let's return something and if this is false let's return something else let me now paste the both buttons again back or the one button into both spots and if this is true we will now actually redirect to D / new so this is correct but if this is false let's redirect to uh SL dasboard SL billing so I can now save that and if I now go back and now hover over create a new note on the bottom left corner you now see that it still links to/ dasboard slne but if I now actually sign out and sign in with a new account which does not have a subscription so let me do that real quick so I have now signed in with a new account which does not actually already um I guess exist exist or does not have an active subscription and if I now hover over the button you see it now links to/ dasboard SL billing now I also have to do the same for this button so let me just copy this whole turnery let's go right here where we have this button where is it actually uh right here we have this button and I will just copy and actually paste it and if I now go back and hover over this button um let me first of all maybe refresh the data and hover over the button you now see it also redirect to/ billing so both buttons now redirect to/ billing let me actually click on a button and now you will see we got redirected to/ billing so this works perfectly now which is quite nice so what can we do now well I think we can actually now almost deploy our application because before I actually deploy our application I want to talk about one error which we currently have so in development environments with next shares our pages are not actually cached but this is is actually a problem because when we deploy our application to Vel our data will be automatically cached and then the problem would be that we wouldn't get any fresh data but everything would be static and we don't want to do that so what we have to do for example for like the settings page we have to tell NEX shares hey please don't cash this page leave its um Dynamic and yeah this shouldn't be cached so we have to explicitly tell that next shares and then next shares will I guess tell it forell how ever you want to see that and for that there's actually an very handy function provided by next shares so let me show it to you so what I can import right here from next slash is unstable no store and we can do an as no store and with that whenever I use that I tell my page hey please don't be cached or I tell Vel in that sense please don't cash this page please make a dynamic so where do I use it now well I use it where I fetch my data so I fetch my data and this acing function get data so let me use the snow store right here but now we actually have to add the snow store function everywhere where we fetch data so let me actually copy this import statement right here let's go inside of this layout. TSX we also have to import it right here since we fetch data uh I don't need the revalidate path right here I only need no store then we go where we fetch our data that's this async get data and we can now use it right here so no store and we can call it then let's go right here inside of the page .x we again have to do the same so let me just import it right here I can delete this old import and let's use it also right here inside of this async function get data let me add no store right here and then also call it then let's go inside of this uh new page so page. TSX inside of this new folder and then right here I actually also have to add it since we don't directly use an Asing function get data but we actually use kind to fetch our user so let me actually import imported right here so our no store I don't need this revalidate path right here I can delete it from here and let me just call no store now from here also now let's go inside of our ID and then also right here in the page. TSX now right here we actually use an async function get data so I can also use it right here so let me just call it right here where we actually get our data then let's go inside of the building page and also call it from here since we also have an async function get data let me add the import right here I don't need revalidate path in this page and let me call it inside of this async function get data now where else do we have it we have building I think the last page is right here the um index page or I'm sorry not the index page but the root layout since we actually also fetch data inside of this root so right here we uh get an async function get data so let me again add the import and we don't need the revalidate PA function I only need no store and then I can just add it right here now this should actually be already all for the caching side of things and I think we can actually deploy our application let me now think about it if I'm missing something now maybe one thing we can add just to prevent the error since this error just comes every time when you use next shares and Prisma that's to add and post install script if you didn't know um the issue with NEX shares or with verel I'm sorry verel is in serverless platform and the problem is then that it actually caches the build generation so we have to actually tell Vel that it has to um automatically run a Prisma generate command when we deploy our application if we don't do that we'll get errors so I just added right here this post installed script so post install and this just says Prisma generate now this should be all actually so let's actually test out and deploy it so let me now go to github.com actually and first of all create a new GitHub repository so I'm now at github.com new to create a new repository let's give it a name of Marshall SAS I think this should be fine and yes this is as you see right here available I will make it public and then let me click on create repository then right here you now see instructions on how to create your repository so let's do that I'll will open my terminal stop the death server right here then right here let's do a git in it to initialize a new repository let's do and get add everything within dot let's get commit - M and let's just say finished project let me click enter and then I will right here copy this git Branch uh M main so I will paste it right here let me copy the remote origin I will paste it right here and then at last let me copy this push command enter that and now our code will be pushed to GitHub as you see right here so let's go back let's actually we load our page right here and now you see the code right here so I'm now at ver.com new so I can right here now click import for Marshall SAS and before I click anything there's one important thing we have to add environment variables so let me actually go to my EnV file let me copy paste everything and just add it inside of here now there's one important thing I want you to know I will now click deploy now this is actually very interesting I got zero errors in the deployment hey it was in successful deployment cool right so we have now loaded our app right here and you see the index page now before I click sign in or sign up I know we'll get an error because there currently the call back is not configured correctly let's first of all see if light mode works I know interesting Let me refresh the page and yes it works it uh it's being kept persistent let me now actually go to the kind of website since I will actually have to add a few callback URLs so let me actually open a new tab and let's go to kind so I'm now at kind.com and I'm actually in the dashboard as you see right here and what I want you to do now is click on settings right here then let's scroll down let's click on applications and let's click on view details now right here as you see we have currently two callback URLs So currently an allowed callback URL and then also an allowed lockout redirect URL now currently both are loow 3000 but we want to actually get our um URL right here so I will copy this URL actually let's paste it right here down below for our allowed call back URL and then let me copy the/ API SL off slind callback I will paste it now right here and now we have a new URL of Marshall s.l. app API slof slind callback it's now of course important that you change the url right here to the URL which you get course your url will of course not be the same now for the allowed logout redirect URL let me again copy my URL and then just paste it down below let me uh Delete the slash at the end so that I just have at the end this Dot app please do the same and now let's click on Save don't forget to save it's very important so now you see it has been successfully saved let me now actually go back to the cell and now right here in ver cell we now have the kind client ID kind client secret nothing changes right here the kind ISL also does not change but the kind site URL does now change so let me click on edit right here and instead of using low close 3000 I can just copy it from right here it will be h gtps Marshall d.v. app I will copy it and just paste it right here again it's very important that at the end you don't have slash but it ends with app now let me click on Save right here now the next thing we have to change is the kind post lock out redirect URL so let me right here click on edit and this will be again the same URL which I've already pasted right here for the kind issuer URL now it's again important please don't add the slash at the end leave it with app let me now click on Save and then the last environment variable which we need is the kind post lock and redirect URL let me click right here on edit actually and what we have to do now is again instead of local 3000 I will just paste my actual URL SL dashboard let me now click on save so now we have added all environment variables for kind so in theory kind is now done but one thing which is currently missing is the stripe rep hook secret so let me go to stripe right now so I'm now in stripe as you see now let me click on developers then let's click on web Hooks and then right here let's click on ADD endpoint now right here I have to add an endpoint URL now the endpoint URL will be actually my URL so I will copy paste that um/ API slash web hook and then slash stripe now I want you to make sure that you spell the endpoint URL correctly because if you don't do so uh this web hook won't work and this is of course not what we want so now we will listen to events on my account this is correct so right here the first event which we need right here is the checkout session. completed so let's search for checkout and this is right here check out session completed and then the next event which we need is the invoice payment succeeded so let me search for invoice payment so invoice. payment. succeeded let me click right here and now let's click on add events so we have now in total two events and that's good and I can click on ADD endpoint now what I want you to do is right here click on the signing secret since that's what we need for our web hook secret I will now just copy the value let me go to the cell and add it right here for the stripe rep hook secret let me click on edit and let me just paste the value right here now you see it's a bit shorter than the test variable but that's fine I can now click on save this will now also add to your environment variables and now I can click right here on the deployments tab and just click right here on redeploy this will just redeploy our application with the new environment variables so now let's actually wait for it to be deployed so our application has now been successfully deployed as you see right here and while waiting for the deployment I already knew I forgot one thing to add but that's fine let's actually see it in production when the error occurs let me now click right here on sign in this will now redirect us to the kind website so let's see now right here I will again just loog in with my Google account so let me do that real quick and now you see I got redirected to/ dashboard if I now hover over this link I can actually create a new um note so let's right here just write something hey super cool and some gibberish for the description let me click on Save now we have this beautiful pending State as you see right here and we now actually get redirected to/ dashboard so this works let me now for example actually delete this note again you see we right here have in pending State and it has automatically revalidated the cache let me now click on settings right here you see now the settings let me change the color scheme to Orange let me click on Save now you now see that it has been changed to Orange let me click on billing right here and right here you can now see I can actually view my payment details so let me click on view payment details and now you see I will actually get redirected to our stripe dashboard which is cool let me again now click on to go back and now you'll see the problem we got redirected to Local Host 3,000 this is not what we wanted right but don't worry we will fix that before we do that let me again now sign out and sign in with a new account which currently does not have an subscription so I now signed in with a new account which does not have an subscription if I now hover over create new note you will see I will get redirected to our billing page let me click on create subscription this should now actually redirect us to stripe checkout so what I can do right now is just add some card data so let me do the test card I will now click on subscribe and now we should actually get redirected so where will we get redirected it will probably again Below close 3000 and you see we got redirected to low close 3000 SL payment SL suuccess now let's again first of all check if our web hook uh actually worked so I will just reload the application right here and right here I should now be able to create a new note let me actually hover over it and yes you see I can now create a new note and that's because we she got the web hook event and we updated our database with a new um active state for my account great right it's fully working so now let's fix this little problem with the URL and then we'll be done for today so what we can do right here in our environment variable is just add a production URL and then for the value I will just copy my URL right here so Marshall says. app so I will paste it right here let me save that and now let me actually open our building files so page TSX in the billing folder and then right here you see we have two Asing functions so the create subscription function and the create customer portal function what I can do right here now is actually again use theary so if the process. EnV do note EnV is equal to production let me right here return a process. EnV do how did we name it we named it production URL I will copy it paste it right here as string and if this is not true we will actually use local 3000 as you see right here now right here shouldn't be in question mark But in colon and now you see we don't get any error anymore one thing I will do right now in our EnV let me uh Delete the slash at the end I only want the app at the end now we'll also do the same for the customer portal right here so let's try do a process. envy. note Envy if this is equal to production let's right here useing uh question mark and let's return process. EnV dot I want to have this production URL so I will copy it and paste it just to be sure and if this is not true let's use some colon to return uh low close 3000 dasboard now this should be actually working so let me first of all go to my EnV let me copy this environment varable so our production URL let me go to the cell right now I'm now in V cell let me click on settings let me click on enironment variables and let me just add this environment variable right here now let me click on Save and right here we have to now push our code to GitHub so let me again open my terminal I will clear everything let's do a git add everything within dot git commit DM and then let's just say addit new EnV let's click enter and let's get push this will now again push our code to GitHub and you'll see right here if I click on deployments that verell will automatically rebuild our application which is quite nice so now let's wait till it's done so so now it has been again deployed so let me click again on our new URL and now we should see I'm again in our dashboard I can now click on billing I can click on view payment details will be redirected to the swipe dashboard and if I now click to go back you will see I will now get redirected to our actual URL and not anym to low close 3000 let me again create a new note so let me right here WR some title let me create some description some gibberish let me click on Save now I will now get redirected again to our dashboard let me click onedit to edit our note let me just delete at the end this ASDF and right here let's just add some more description let me click on Save now we will again get redirected as you see I can now delete the note again then I can click on settings right here that change the color scheme to green or let's actually change it to Yellow we didn't have yellow right now and now you will see this will also uh change which is great right so you see everything fully works now so now I think we're actually done so thank you guys for watching I hope you could learn a lot thank you kind for sponsoring today's video and now I hope I can see you in the next video so bye
Info
Channel: Jan Marshal
Views: 64,725
Rating: undefined out of 5
Keywords: nextjs 14, nextjs 14 typescript, Create a saas, SaaS Nextjs.14, Next.js Authentication, Kinde Authentication
Id: 5dgYg10B9p0
Channel Id: undefined
Length: 253min 53sec (15233 seconds)
Published: Thu Jan 25 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.