Next.js 14 Netflix Clone using React, Supabase, Next-Auth, Prisma and Tailwind.css

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so you want to build a full stock Netflix clone using NEX shares 14 next off for authentication Prisma and superbas to qu our database and T1 CSS and shaten for beautiful styling so what exactly will we build in this tutorial so we will build a fullstack Netflix clone as I already said using next shares 14 and the newest features that it offers that means Advanced routing and server actions then we will use next off to make Authentication work we will use GitHub o off Google o off and email passwordless off at last we will style our application using TN CSS and shetan UI which provides styled and accessible components so with that out of the way let's check out the beautiful demo behind me and now I hope you enjoy this video and let's go so on my screen you now see what we build today so this is the default state which you come to when you're not logged in so so this is the login page I can click on sign up or on log in whatever I want to do you also see that the background image is not rendered which means that we use layout routes and for that we will use route groups which also means that it won't get mapped to the URL now I can log in with whatever I want I will choose Google and then once I'm signed in I will get redirected to /home so this is now the homepage that you see now the first thing you see is this video player right here on the top I can now click right here on learn more then I see more about the video the title description a bit of more uh data right here and the trailer I can then see the Recently Added movies right here I can again click on them to play the trailer if I want to then I can also add them to my favorites as you see right here and the nice thing is they automatically revalidate that's why I see now this red heart icon then on top I have multiple categories so TV shows for example movies right here or the the Recently Added movies and again I can click on them if I want to then the last nav link which we have is my watch list there you have the watch list items which I've just favored I can also of course unfavorite them which means they will get unlisted from this watch list so let me also unfavor this and now this is an empty watch list this project is also completely mobile friendly so I hope you enjoy this video and now let's go so to get started I will CD into my desktop directory CD into my YouTube directory and I will run npx create-- app at latest to install the latest package of next shares the CI will now ask me for name so let's name it um Netflix clone dyt then we'll use typescript we will use eant we will use Tailwind uh we won't use the source directory since we will use the app router and we won't customize the default import Alias and now the Cal I will install next shs this will now take a few seconds so let's wait for that so next shs has now finally installed successfully so now let's go to visual studio code and open our project so now I'm at Visual Studio code and as you see I already opened our project and if you want to do the same go right here on file and click on open folder and then open your folder but now as you see we have a very Bare Bones application actually we now have a default template by next shares and let's actually see what we have so let me open my terminal you can either do that with command tray or you can go on top click on Terminal and new terminal but now inside of here I want to start my def server so let's run npm run def so now our def server will open on Locos 3000 so let's go there and let's open that so I'm now on Locos 3000 and well what do you see well you see the default template provided by next shares now that's of course not what we want we want to create our own twist we want to create a Netflix clone so we'll change that in a second or actually let's do that right now let's go right here in our Explorer let's go um inside of our app folder and then inside of our page. TSX that's right now the index page so that's what you see right here let me first of all delete everything inside of here I don't need that and then instead of this um return statement let's create a return with an H1 and let's say hello from the index page if I now save that and go back well that's what you see so what you saw seconds ago was just the default template or the default index page by nexs and now you see we have modified it and that's what you now see in our Chrome browser but now of course we don't want to leave it like that we want to actually create something very beautiful a beautiful Netflix clone and before we can actually do that I want to install a very important package which will need for this project and that's shatan UI so let me go to the website so now I'm on ui. shen.com and again if you want to go to the same URL go to my YouTube description and click the link but now if you don't know what chatan UI is well it's a component library and this component library is actually built on redex UI and redex UI is a component Library which is not styled but accessible and now shatan UI Builds on the fundament of RX UI and actually Styles them so that's why we'll use them right now and for that let's go on documentation let's click on installation and then for the framework we'll use next shares then right here you see a quick start guide and now we have already done step one which is to install next shares so let's go to step two and now actually run our C and install shaten so let me copy this right here and I will use npm as our package manager then let's open our terminal then let me stop my def server right here let me clear everything and now let me paste the CLI right here or the CLI command actually now the C will ask us a few questions first of all would we like to use typescript yeah sure let's use that um let's use the default style for our base color we will use slate then uh our Global CSS file let's see where it's uh located you see it's inside of the app folder and it's called global. CSS so that's correct as you see then we'll use CSS variables where's our T.C config.js located well as you see right here our T.C config dots is provided inside of the root folder but now we have a discrepancy right here we have a T.C config.js but inside of our project since we use a typescript project we have a TS so let me change that instead of a t on config.js let's do a TS that looks good now uh our import Alias is is correct we will use add/ components for our import Alias for utils let's also leave it like that that looks fine then we use server components since we use the app router with next shares 14 so let's use yes and then let's write a configuration file for components. Json so now that looks good and let's wait for a second so now we have installed successfully um shatan UI and before we actually test it out one thing I want to do right now if you go back and click on the na bar on themes you can actually create your own theme or not create your own theme you can do that but you can also choose the theme right here which is already provided so you can for example use right here a red color green color violet color that's the base colors which you can use but what I want to use is this thing color right here so what I will do is click on copy code this will now split out the CSS variables which I will need so let me copy them then I will go to the global. CSS file and and then instead of this default CSS variables let me delete them and paste what I've just copied now also one thing you'll see if you go to our T.C config.ru has now created a bit of configuration files so right here we just use our colors so which we have provided right here with CSS variables and give them right here name so our border has then our CSS V variable which is right here D- border now also if you go to our package.json what you'll see is that we've also installed a few packages with shets and UI so for example right here this class variance Authority or CLX or tent merch or tent animate um that's not very important that just needed for the components to make them look nice but a important thing and a nice thing is that also locd react is installed and if you didn't know actually Lucid as an icon library and you can also follow this link so let's do that right uh real quick you will see right here that lucid is a um icon Library which is very nice and also has consistent and beautiful icons as you see right here and we can now use them actually inside of our project without copying any SVG code so that's very nice and I also really like this icons actually but now let's actually test out Shaden UI to see how it looks like so I will now go back to the shatan UI website let me click right here on components in the nav bar and and now let's actually just install a button right here so right here you have an installation CLI command let's just copy this whe again use npm I will open my terminal clear everything and paste the command this will now just install the button and you will see in a second now if I close my Explorer everything you will see right here we have now a components folder with a button. TS file and now as you see this is actually an RX UI component which is styled using shat CNU so Shan UI provides nice default styles for us which we can also actually override if we want to do that but I don't do that since I think they already look very nice so now let's see how it looks like so let's go to our index page and now um right here let's create this return and then uh let's create a div element so let's do that and then inside of here I will now import my button and this is uppercased as you see and then you can import that from at components UI button let me do that then let's say um hello from chat um CN UI and let's create also underneath it a H1 hello from the index page if I now save that and go back and reload everything you will see our def server is not running so let me open my terminal and let's start our def server with npm1 def this will now again take a few seconds so let's wait wait for that and now if I reload the page that's what you see right now we have the shadan UI button and if you hover on it you actually also see hover Styles which again shows you how the default styles of shaten looks like and you also have an H1 tag let me actually give it some margin you see it a bit better so let's give it a class name of margin 5 if I now go back yeah that's what you see you see a button and ah1 tag now there's one thing right now you see our background is white now that's actually not what I want to do um let me actually open My Demo real quick so what do you see right here well actually our theme is dark so um if I would reload this page real quick you saw this little flash of the back background color and again if I go back right now to our local 3000 our background color is white but I want it to be black so let's change that real quick and to change that what we have to do is go right here to our global. CSS files and then right here inside of our layer base what I want to do instead of giving it a a BG background I will give it a BG of black and then let's save that and let's go back well that's what you see right here now we have this button and we have an H1 but you can't see that now that looks all right but it does not really look good so first of all our button is 100% not accessible you don't even see that that's in button since the background color is actually I think it's also black I can't see it really and then our H1 tag is also black and again you can't see you can't see black on black you want to see white on black so you have to change that so inside of the global. CSS again we have our CSS variables and now you see we have two I guess tabs we have right here for our back uh for our white mode and then we have a class for our dark mode but again since I want to use this page only in dark mode I want to force shatan UI to also only be on dark mode so what you have to do is right now copy everything inside of this dark class and then right here we have everything from background up to ring let me delete everything the only thing I want to leave right here is the dash Das radius and then let me paste that inside of here so again I've deleted everything inside of this root just not the radius and then I've pasted everything from dark so from the dark class name and if I would now save that and go back well what do you see our button is not black anymore but white and our text is not black anymore but it's also white again that's because we have now manipulated I guess shui to tell it that we are on dark mode even though we are actually just on white mode but that's all right because I only want to run this website in dark mode and not in white mode so now I think we can actually continue and now create the lockin and the sign up Pages now before I do that let me again open My Demo right here now now what's one thing you see if I click on sign up now and click again on loog in now do you see reenders well yes you see a reender for this block right here so the black uh the Black Block does reender you see this little flash when I route on uh when I click on this route button but what does not reender that's actually right here our background image this Netflix background image and our logo it never reeners but now that's strange right because if you go right here to our URL and now if I click on sign up you'll see that we have an slash sign up but we don't have an um parent um layout so we don't have for example a slash off/ signup and a slash off/ signin but we just have a slash signup and a/ login and now the question arises how the hell do I create a parent layout without creating a parent route in that sense and for that next sh with the app rower has created a very cool feature which is called route grouping so let's check out the docs so now I'm at the next sh docs and right here I'm now at the route groups and we can actually read it right now so inside of the app directory nested folders are automatically mapped to URL paths that means if I would now create a normal folder inside of our application right here so if I would now go inside of my app folder and create a folder what you would see is we would create a path so for example SL off but with rout grouping you can Mark a folder as a route group to prevent the folders from being included in the route URL path this allows you to organize your route segments and project files into logical groups without affecting the URL path structure so that's exactly what we want to do we don't want to create a parent route but we want to create a parent group to group the/ login and/ signup page so how do you do that in the docs right here you can see you can actually wrap them with this parenthesis you just wrap your folder name inside of parentheses and with that you have created a route group so let's do that right now inside of your app folder create a new folder and now let's wrap it in parentheses and let's say off now we have created a route Group which is called off and now inside of here we can create two new folders so first of all let's create a lockin folder for our lockin page and then inside of the off folder let's let's also create a sign-up page now for our login page let's create a page. TSX let's do also the same for the sign up page so let's create a page. TSX and now let's actually create our UI now a second ago as you know already I have already talked about our layout and rendering so again to reiterate I want this background image to stay as in layout so I don't want to rerender it once I um change routes right here so how do I do that well inside of our route group off I want to create a layout. TSX file so no folder but just the file which is layout. TSX now inside of here uh as I always have to do I have to create a export default function so let's do an export default function let's name it um I guess off layout and let me open this um export default function now inside of here I can now return something so let's return a h one and let's say hello and what I want to do now is underneath this ag1 show my children and with children I mean the lockin page and the signup page now how do I get my children well I get them through the params so let me D structure children and now I have to give children a type so children will be of type react note and react note as you see is imported from react now underneath this H1 I can now just paste my children and now now I have also to wrap this age1 and children in a diff tag so let me do that and now I can save that now let me go right here again to the Explorer let's go to login and then inside of this page. DSX let's create a export um default function let's say login and let me open that function inside of here I can now return something and let's say H1 and let's say hello from um the index page and that's save that so what I can do now is let's go back to Locos 3000 and now inside of our URL let's go to/ login now what do you see right here you see a hello and hello from the index page now if I go back to the layout. TSS so where is it right here we just say hello let's change it let's say hello from the layout and if I now save that and go back you now understand what we see we have a hello from the layout and hello from the index page and again as already said if I would now go to the sign up page which right now won't work we will throw an error since we don't export default a function but if I would do that then the root layout would still say uh stay consistent and it would not reender and then this children right here so hello from the index page would just be uh would just go away so again let's just actually test it out so let me go to sign up and then instead of the page. TSX Let's do an export default function sign up and let me open that function inside of here I can return something and let's say H1 hello from sign up if I now save that and go back you won't see anything but if I now go instead of Slash login to slash sign up so sign Dash up what you see right now is we have still this hello from the layout but now instead of hello from lockin we have hello from sign up so that's what we have just created we have created a layout which is shared to both routes but the individual route can have different content and it's always right here rer if you go to the layout. TSX inside of this children that means under the under this H1 tag so now with that out of the way let's actually create now the background image and the nav bar for our off page so to do that let me delete this H1 tag instead of the layout file since I won't need that anymore and then for our diff element let's give it in class name of let's say relative let's give it in Flex AG which will be screen we'll have an W which will be screen then let's give it an Flex of call BG of black and MD will be items of Center let's give it also an MD of justify Center and then let's also at last give it an medium of PG transparent so now inside of this diff element I want to render my background image and my nafar or my NAFA logo and now where do you get the images from well you can go to my GitHub repository click on code and then just download it as zip then inside of the public folder you'll have all the images you need so the background image is right here loog inore background and also you have right here Netflix unor logo but again all you have to do is go on code and click on download zip but now I will go back and as you see I already put all of the files right here inside of my public folder so the lock and background the logo and the Avatar but now let's use that so inside of the sff element and about of the children let me use the image tag provided by nextjs and that's imported from next / image and now why do you use this image component well if you go to the docs the next's image component extends the HTML image So in theory the image component is still the same at the end the HTML will still have a normal image tag but it has uh features so for example size optimization visual stability faster page loads and asset flexibility so that's why we'll use this right here and not the normal image tag so now we'll first of all have to give it in source so let's give it in source and for the source I will first of all have to import the image so on top let me write import let's import a background image and from let's say do slash dot do slash public and then this will be the lock in background doj then inside of the source I can now pass my background image now I also have to give it an Al tag for the alt let's just say um background image then let me also give it um a class name now for the class name I want to first of all give it a hidden since I don't want to show the background image on smaller devices and I only want to show the background image on bigger on bigger devices so first of all the class name will be hidden then uh when we have a smaller device so SM I want to show the image so I will give it an flex and let's give it also an SM of object cover and then I also want to give it an A Z index of minus 10 so let's give it in minus Z of 10 so now if I save that and go back and let me reload the page well you see now the background image but now there's one thing if I reload the page actually you will see this little black screen that's fine but if your network is smaller uh slower the image will actually take longer to load and then you will see this uh black uh back background even longer so if you open your Network tab right now so let me open that and if I now reload the page you see that the image is actually just loaded right here so we load all of this stuff and then we just load the image but what I want to do is actually load the image within priority so I want to load the image actually pretty early on when we refresh the page and for that actually next shes has a very nice property or the image component and that's priority and with that I just load the image within priority so if I now right here click on uh to delete everything from the network Tab and if I now reload the page you'll see that the image is not anymore loaded right here somewhere in the middle but it's actually loaded as one of the first things so I now load the image within priority also one thing you see right now is our image does not fill the whole screen so you can also again use another property which is just called fill if I now go back you see now the screen actually or the image fills the whole screen which looks quite nice and if I make the screen smaller so um smaller than the small break point you'll see that we don't see anymore the image but just the normal background color so that looks good and now we can actually continue but now there's also one more thing and that's I think the image is a bit too bright so let's tone it down a bit and for that we can use right now in the class name brightness and let's set the brightness to 50% if I now save that and go back well you see the imag is much darker now and you see the contrast much more so now the H1 tag with hello from sign up up Pops much more so now let me continue and now I want to show the logo so on top let me again import the logo so let's do a import let's say logo from do do/ do do SLU and then it's called logo let's see logo or it's called Netflix logo.svg and then under this image tag I want to again use an image tag so let me again use that let's give it in source and the source will now be low then for the alt let's just say logo then let me also give it a class name and the class name will be absolute let's give it in left of let's say four let's give it in top of four then let's give it also an object and the object will be contain and let's give it a medium of left 10 and a medium of um top which will be six if I now save that and go back well you see an logo that's a bito big actually yeah it's too big so let's actually change the size so let's give it in width and for the width let's do 120 and for the height let's also do 120 if I now save that and go back yeah the logo is now much smaller this now actually looks way better so if I reload the page yeah that looks good one thing you again can do if you want to is add an priority tag for the logo so that the logo is loaded within priority so yeah that looks very nice we have now created our layout and now we can create our login and sign up page so let's do that so now first of all let's create a sign up page since we are already on the signup route so let me go right here to the signup folder instead of the page. TSX let me delete this return statement and let me create a new return statement inside of here let me create a diff element let me um give it a class name of margin top 24 let's give it in rounded let's also give it in BG of black and I want the color to not actually be black but I want it to be a bit of transparent and for that I can add an opacity of 80% so I can use the Slash and then I can add any uh number and this would be then the percentage and opacity then let's give it them padding y of 10 padding X of six medium which will be margin top of zero and let's give it a medium of Max withth small and medium of padding x14 and then inside of the stiff element let me create a form element and I won't style it actually and I also won't use an action right now and then inside of here let me create a H1 tag and let's just say for now um sign up if I now save that and go back well that's what you see right now you see this black background color and you see an H1 with sign up and again if you want to change the opacity you only have to change the number the number at the back so you could now use an 70% opacity and then you will see that the color is a bit more light but I will leave it an8 at 80% since I think it looks uh quite good but now let me style first of all this H1 tag so let's give it in class name let's give it in text which will be fre XL let's give it in font which will be semi bolt let's also give it in text which will be white if I now save that and go back you now see that the signup text is actually a bit bigger and this looks even better so now under this H1 let me create a diff element and let me give it in class name of space y4 and margin top of five and then inside of here what I want to now create is an input and a button to sign up and for the input I want to use a shaten component so let me again go to shaten UI and I'm now again on shatan UI so let me search for input then we have it right here let me uh go to installation and copy the command let me again open the terminal I can right here now click on just new terminal and and then just paste the command right here this will now install our input let's wait a second and now I can use our input which is upper case since it's in component I will import that from add components and this is in self closing tag then uh under the input let me create a button and this is again a component so let me import that and right here let's say sign M up if I know save that and go back well you now see an input and you see a sign up button still that does not look good first of all the input you barely see that right now and the sign up button it should be red and not white so now first of all let's style our input so let's give it a type and the type will be of email let's give it a name and the name will be of type email then let's also give it them placeholder and let's say email let's also give them class name and now for the class name first of all let's give them background and I want to use some custom value and for that you can use this array brackets right here and then let's give give it an hashtag of free free free if I save that and go back you now see that the background color is a bit more visible and I think that looks better then let's continue I want to now Target the placeholder right here and then let's go it in text which will be XS let's also Target again the placeholder and then let's give it in text which will be gray of 400 and let's give it in W which will be full and in line of block if I now save that and go back you see this looks very nice in my opinion and you can now actually see that that's an input now let's also style the button so let me give it a class name which will be W or full and let's give them BG and I again want to use the custom bracket since I want to use some custom value and the custom value would will be # E5 914 now if I save that and go back this is now the button again this is still not good our text right here is black and if I hover on it it's white so I can add a variant to the button so let's give it an variant and the variant will be destructive if I now save that and go back you see that that looks way better I have now in Hover effect and the text is white and not black anymore also one thing you can do right here is also go in type and the type will be submit since I will want to submit the form with this button now under the form I want to create another diff element so let's create a diff element and then inside of here I want to say um already have a account question mark and if so let's create a link component and the link component is first of all imported from next SL link and again this is just the normal a tag but with superpowers so for example prefetching and client side navigation now it types skill complains to us since we have to pass a h tag so for the h let's give it an slash of log in and then inside of the link let's just say um lock um in now um exclamation mark if I now save that and go back you right here now see already have a account loog in now let's style that that does not look good so for the diff let's give it in class name of text which will be gray 500 text which will be small and let's also say margin top of two then for the link component let me also style it so let's give them class name of text which will be white and hover which will be under line so now if I save that and go back you see this looks very nice and you now actually see that this is in button or in link actually now underneath that I want to now create two buttons so a Google signin button and a GitHub signin button so let's do that right now to do that go under your link component and under the div and let's create another diff element let's give it a class name which will be Flex W your full justify which will be Center let's also give it an items of Center and let's give it an gap which will be X of three and margin top which will be six inside of here I want to now create the Google signin button and the GitHub signin button so for that first of all let's create again a button and we'll use the button component then inside of here let me give it in variant and the variant will be just outline then let's give it also in size and the size will be icon since I want to use an icon inside of this button and then let me right here render our icon and we'll use the GitHub icon provided by our um icon Library so let me open right here our GitHub icon and this is imported from Lucid D react this is in self closing tag and if I now save it and go back you now see this GitHub icon right here I think that's a bit too big so let me give it uh this GitHub icon in class name so let's doing class name of uh W4 and H4 if I now save that and go back yeah yeah this looks very nice and we also have a nice hover effect now let's also create a Google button so let me just copy this button and let me paste it again and now we have two GitHub icons and now for the Google icon sadly Lucid react does not have an icon for Google so again we have to import that um icon so let's go right here on top and let's do import um Google icon from um do SL do do/ do do SLU and I think it's called google. SVG and then I can instead of using this GitHub icon I can use a image tag and image tag is again provided by next SL image and then inside of here let me pass the source which is um Google icon let me give it an ALT tag and this will be Google icon and let me get in class name which will be W6 and H of 6 if I now save that and go back yeah this looks very nice we have now two icons first of all the GitHub icon icon and the Google icon now let's create a login page so if I now click on login now you see you'll get the redirected to/ login and we only have this H1 text so let's change that and create a nice login page so for that open your app folder go inside of your off and let's open the login and then page. TSX now we could again just do everything manually or we can just go to our signup route and actually just copy everything so let me copy this whole div element or everything which is inside of this return statement and then inside instead of this return statement I can just paste right here this now let me import uh my input right here from components let me import the button also from components let me import the link which is imported from next SL link and let me import our GitHub icon from locid react and then I also have to import our image component so uh it does not sadly import automatically so on top Let's do an import import image from um next SL image and I have to import the Google icon so let's do an import Google icon from do/ do do/ dopu and google. SVG so let me copy that and instead of Google icon let me paste the different name I've created if I now save that and go back uh let me reload it you see now our lockin page and sign up page are both the same so now let me change the lockin text to actually be equivalent to the lockin page so for that instead of an H1 with sign up let's say lock in then right here in the button instead of sign up let's right here also say loog in and then right here instead of already have an account let's have a different question with new to Netflix question mark and if so let's say sign up now then we'll also have to uh change the HRA instead of Slash login let's say slash sign- up and I think that's quite good so if I save that and go back yeah that looks good log in email log in new to Netflix sign up and the two buttons so if I now click on sign up we'll get redirected to/ sign up and if I again click with here lock in now you see that works perfectly and you also see that the background or the layout does not change so the background image does not get reender and only this um I guess this back uh this black background color will get uh rendered but everything else is static and does not get rendered so now we have created a login page and a signup page and now let's uh create the functionality to actually sign up or log in now to make authentication work in this project we will use next off and if you didn't know next off is a open source project which is actually also sponsored by verel and the creator also works now for and I think it's a very great package and I think it's also quite easy to use maybe a bit more complicated than for example clerk but I think it's very nice since it's free and very extensible so what we have to do now is right here click on documentation let's go on getting started and then right here let's uh copy this uh install command so npm install next off let me open my terminal let me right here clear everything and let me paste the command to next off so once that's done we can actually continue with setting up next off so right here let's uh continue with the quick start guide and it tells us to add an API route so to add a next off JS to a project create a file called dot dot dot next off. JS in the pages API off folder but now we don't use the pages folder we'll use the app router and for that it tells us right here if you're using next shes 13.2 or above which we use we SN NEX S14 with the new app router you can initialize the configuration using the new route handlers by following our guide so let me click on this guide right here and again I would also encourage you guys to also go to the documentation and do the same since it will be much easier so right here now it shows us how to exactly create our route Handler or in that sense our API route so what you want to do is go right here inside of your Explorer go inside of the app folder then let's create a new API folder then inside of the API folder I want to create a off folder and then inside of the off folder I want to create this right here um this inside of the array brackets this dot dot dot next off so I will now just copy that to be sure to not misspell anything and now inside of this app folder let me just paste that so dot dot dot next off inside of array brackets and now since we want to use route Handler so and we want to create an API route we have to uh create a new route. TS inside of this dot do dot next off folder now inside of here you see what we have to do we have to import next off then we have to initialize our Handler and then export our handlers and get and post request so let's actually do that so what we want to do right now is right here import next off so let's you import next off from next off/ next and then I want to create a Handler so let's you in const Handler which is equal to next off and then right here I have to pass my off options which I will do in a second and what are off options well actually this is just the file in which we'll uh tell next off what providers we want to use so in that sense GitHub um Google and email so we'll create that in a second and now the last step what we have to do is export our Handler as an get and post request so let's you export as an object Handler as get and I want to do a Handler as post so now since cycript still complains for right here and it tells us expected one to three arguments but got zero let's actually create another the options and for that let me again open my Explorer and then inside of the app folder let's create a new folder called utils and then inside of the utils folder let me create a new file called off. TS so what do we want to do in this off. TS file well again we want to create off options and inside of the off options we want to define the providers which we want to use so what we want want to use is the guar provider the Google provider and the email provider for example and to actually see how it works let's go to the next off um docs website so I'm now on the next off website and I think actually if you're new to next off the docs can be a bit I guess complicated at first but once you get the hang of it it's actually quite easy now right here you have first of all providers and you also right here if you scroll down have adapters now what's the difference so the providers is uh for example Google uh email GitHub Facebook so everything which you can use to authenticate and then what is the adapter well the adapter is where you store your user information so the session the user data Etc and for that you have multiple possibilities so for example drizzle orm Firebase U mongod DB Etc but we'll make it very simple we will use Prisma for that and now you'll see if I click on that we'll get redirected to the off. JS website and it will tell us how to get started with that so first of all we will have to install Prisma so let's actually copy the command right here and again I would highly suggest you guys to also go to the website and also uh follow me and copy everything from here so I will copy the installation command I will open my terminal and then let me paste it inside of here so what we do right here is install pisma client we install the pisma adapter for um next next off and we also install um Prisma as in development dependency as you see right here this will now take a second so let's wait for that so now you see Prisma has been installed and also the Prisma adapter so now let's actually initialize Prisma so what you have to do is an npx Prisma in it to initialize Prisma so what you will now see is that um Prisma has actually created two files or one file and one folder so a EnV file where you store your secrets and then also a Prisma folder with an empty schema right now also right here they give us a warning a warn you already have a dogit ignore file don't forget to add a EnV in it to not commit any private information so let's actually follow this advice and do that since we don't want to um push any of our secrets to GitHub so right here inside of our g. ignore let me add a EnV file just to be safe so now with that done if you go to the EnV file actually so let's go there where is it EnV here here is it you will see we'll have a database URL now this right now is just a default empty database URL which does not work and we have to create our own database or our own database URL and how do we do that well we'll have to use some provider and I will use for this project superbase which offers a post database so let's go to super base.com so I'm now on superb.com and if you didn't know superbase is an open- Source alternative to Firebase and I really like it I like like it more than Firebase or any other alternative and the cool thing that they have is that they use post Quest database they offer authentication instant apis Edge functions and much more but for our project all we need is in database and for that we will now use super base so if you already have an account click right here on dashboard or if not create one then let's click on new project right here I will choose my organization then for the name let's just name it Netflix nextjs M14 then for the password I will just generate a password right here and then copy it since we need it in a second and actually let me also um paste our password right now in the EnV file since we will actually need it in a second then for the region I will choose Frankfurt since it's the nearest to me and then let me click right here on create new project which will create a new super based project for me now this will take again a few minutes I I think about 2 minutes so let's wait for that and once that's done I will come back so as you see now our project has now finally initial IED so what I can do now is Click right here on settings on Project settings then let's click right here on database and then right here we have our connection string which we'll need right now so we don't need the psql uh string but we'll need the URI so let me copy that and now instead of this database Ur let me delete it and paste what I've just copied now right here you see I have to pass my password so I have copied it right here already so let me copy it again and instead of your password let me delete that and paste my actual password and now since we have now initialized our Prisma or in that sense our database and uh created the connection we now have to create a schema since if you right now go to your schema. Prisma you see that it's empty and we want to create a schema where we can store the user data the session Etc so if I go back to the off. JS website where we have installed Prisma and if I scroll down to the setup you see right here that I have to add an adapter to my off uh options configuration object and there you see we have to add our adapter then we have the Prisma adapter function and we have to pass our Prisma client now in this example they create a pisma client uh right here just so con pisma new pisma client but this does not really work good with next shares you have to create a global Prisma client to not uh get any errors so if you right now go to Google and search for um next shs best practices Prisma what uh and if you click on the first link right here what you will see is right here a problem a lot of users have come across this warning while working with next shares in development and the warning is there are already 10 instances of Prisma client actively running so what happens is since you use an next HMR and when you wait uh when you make a change and save your file well actually the application reloads and you will create a new Prisma connection and you don't want to do that in development you would only want to do that in um production so what you have to do is actually right here's in solution where you check if you're in the development environment and if you're in the development environment you create a global Prisma client and if you're in production you just create a normal um Prisma or new Prisma client so let me just copy this file you can either do the same go to Google and search for that or go to my um GitHub and copy it from there so what we'll do right now is open my Explorer then go inside of the app folder utils and let's create a new file called db. TS and let me paste that inside of here so again we just uh check if we're in development and if so we create a global Prisma client and if it's the opposite we create the normal Prisma client and now with that out of the way let's go back and right here again they already tell us to right here just pass it in our off options but if you can remember our off options right now are empty we haven't created that right now we'll do that uh in a second first of all right here we can create a Prisma schema this is very important since again you want to store your user data so what I will do right now is just copy everything so everything from model account down to the bottom which is let's see down to the verification token so let me copy everything and then let me go back to our schema and let me just paste it down below and now we actually also have to push the schema to uh super base since our super base uh schema is now empty so what you have to do is s npx Prisma DB push to push the schema to our remote database uh at super base now our uh schema in sync with super basee and that looks very nice what we can do now is actually create our off options so that we can uh pass our providers so the Google provider the GitHub provider and the email provider so let's do that right now so what you have to do is actually very easy we have to create a we have to export a constant let's name it off options and this will now be just an empty object but now we use typescript in this project so if I now click on control space bar you will see we have zero types and that's of course not we what we want we want to get types and for that typescript has a very nice keyword which is called satisfies so we can use this right here now and we want to satisfy the next off options now these are imported from next- off and this is in type so let's do on top import type next off options and now we get an error but that's fine because if I now click on control space bar you now see we get types based on the off options now the first thing I want to pass right here is the providers and the providers is an array where we pass each individual provider but before I do that if I now go back to the docs you see right here I can now pass my adapter so let's actually do that so if I go again inside of this op and do control space bar you see we can get right here our adapter and then we have to pass our pisma client so what you have to do is go on top let's import and we'll have to D structure Prisma adapter from uh at off/ pisma adapter as you see right here and then I can now um make my adapter equal to pisma adapter and inside of here I have to pass Prisma and Prisma is now very importantly not imported from at Prisma client but from our DB file so from our Global Prisma file now that looks very nice and now this actually also works so now all we have to do is create our providers also let me write here pass and comma to not get any errors and now for the providers I will actually use three providers so first of all the GU provider the Google provider and the email provider and for that let's actually go right now to the next off website to check it out so I'm now on the next off website as you see and now instead of adapters we can click now on providers now what's the first provider which I want to use well that's actually GitHub so let me search for GitHub where is it uh here it's right here GitHub and right here we have a note GitHub returns in field on account called refresh token expires in which is a number CED the docs remember to add this field to your database schema in case you're using an adapter now we have to actually also do that since we want to use skub so now what we have to do is go to our schema right here and then inside of account as you see it tells us right here in a field account called refresh token expires in which is a number so right here in our account I can now just copy this so it's called refresh token expires in let's um put it right here this is of type int and now this is not always defined so we have in question mark since it can be defined or not we are not quite sure so that looks nice and now if I scroll down a bit right here we have an example we have first of all we have to import the GitHub provider so let me copy that let's go to our um off options right here let me import that right here at the top and then let's again copy right here our GitHub provider so we'll copy that and paste it right here inside of the provider's array now what do we do right here we create our guar provider and then we pass two things so first of all the client ID and the client secret now what here you see we pass them as environment variables and why do we do that um well that's because they are secrets and we don't want to pass or we don't want to uh show the secrets to the client so we don't want to get any errors no problems nothing if we store them with environment variables they are stored in the server and they're never shown to the client so there's no tampering to be made with now you also see we get a typescript error and it tells me typ string or undefined is not assignable to type string and that's correct um typescript does not know if our environment variable is defined or not so what we can do is right here use an as string and also right here let's do an as string this is just a little typescript um helper to not get any errors then the next provider which we want to use is Google so let me click right here on Google if I scroll down what do you have to do I have to import our Google provider so let me just copy that let me paste it right here on the top then let me also copy the Google provider right here and let me also uh paste it under the GitHub provider that looks nice and again let me give it the helper as string and also the same for the client secret as string now we have created the G provider and the Google provider and the last one which I need is the email provider so if I now search for email right here which is right here and click on that you will first of all see an overview of uh why you for example should use an email provider and why it's a bit also a bit more safe than the credentials provider so what is the email provider well basically you will get in Magic link every time you log in and with that you don't have to memorize any passwords all you have to do is uh enter email so now if I scroll down right here we want to use SMTP as you see we won't use HTTP but SMTP now there are two ways you can do that either use an connection string or you use right here a configuration object and that's what we'll do so right here let me just copy all of this environment variables so I will copy that and then go to myin v file and and paste it right here down below then if I scroll uh further down a bit you right here see I can now import my email provider so let me copy that actually let's go back to our off. TS file it's right here let me paste that right here and then let me copy also the email provider with all of the options and paste it below the Google provider so this looks very nice now actually and we have now uh created actually everything so the GitHub provider the Google provider the email provider and we have also set up Prisma so that's very nice everything should now work now the only thing that does not work is we haven't created the individual secrets so we don't have a GitHub secret no Google secrets and we also haven't created right now an email service so I think we should do that now I know it's a bit boring since you have to go to the websites create everything but that's what you have to do so now let's first of all go to github.com so I'm now on the github.com website and what I want you to do now is go right here on on settings and then once you're on the settings let's scroll down to the developer settings right here on the bottom then let's click on o off apps and let's create a new oof app right here you see I already had some ooff apps but that's not important now for the application name I will name it next shares 14 next off for the homepage URL this will be low close 3000 and to not misspell anything I will open my terminal and R npm1 def to start my def server right here you see it will open low close 3000 so I will just copy that to be sure to not misspell anything and then let me paste it right here now for the authorization callback URL I would uh highly suggest you guys again go to the next off website and then if you click on Google right here you see right here the configuration and then you see that's our for development um callback Ur So I will just copy that right now right here and even though that's for Google it's not important copy that and then right here paste that and and instead of Google let's rename it to GitHub so we have local 3000 SL API SL off/ callback SL GitHub now let's click on register application and this will now create a new application for us now right here we have in client ID and a client secret so now what I will have to do first of all is if I go back to the off. TS uh file right here inside of our GitHub provider we have a client ID so let me copy this GitHub ID name let's open. EnV file and then under the database URL let me paste that and for the value I will copy the client ID then let me paste it back right here that looks good so if I go back what's the next field the client secret how do we name it it's called GitHub secret so I will copy that paste that and then this will be equal to the value of the client secret for that I have to generate a new client secret and now I can copy this client secret and also you should uh uh copy it since if you don't copy it and uh delete it somewhere you have to generate a new client secret so I will copy it right here and then just paste it so now we have set up GitHub in that sense now let's go to Google and do the same so I will copy the name Google client ID and then paste it down below then what else do we need then we need the Google client secret so let me copy that paste that right here and this will also be equal to a value and now let's go to the Google Website and actually create the client ID and client secret so right now I'm the on the Google Cloud console and now for you it could be maybe something new uh you will first of all have to create an account and also right here on the top you will have to create an organization but I think you will be able to do that on your own it's not very hard and there are thousand YouTube tutorials for that but once you're on the screen where you can create your own credentials then you're all right and now we can actually continue so you can click right here on create credentials and we have to create an O off client ID so let me copy uh click on that and now for the application type we will use an web application for the name let's just say um Netflix YouTube now once the name has been added the last thing we have to do is pass right an authorized redirect URI so let me click on ADD U and if I go back to the next off website you right here already again see this URL for development so let me just copy this whole URL copy opy it and then just paste it inside of here then let me click on create this will take a bit and then we write here getting client ID and the client secret so let me copy the client ID then let me paste it inside of here and for the client secret let me copy it and also paste it right here down below that looks nice we're now also done with Google and now the last step which we have to do is set up email so let's do that now since we want to use an email provider we of course also need a provider with which we will send emails and for that I will use resent in this video you of course can also use any other uh provider for example sent Grid or I think MailChimp or whatever you want but I think resent is very nice to use and also very easy so let's use that now if you don't have an account create one but since I have already one I will sign in right now so once you're signed in and inside of the dashboard let's click on ADD API key right here then I will uh create right here an API key so let me copy it let's go back and then right here for the email server password let me just pass the API key and now that's actually ready everything we need from our dashboard if you now go to this blog article from weent um SMTP service you can right here see how the configuration looks from them again all of the URLs are inside of my YouTube description so you don't have to search anything uh yourself you can just click on the link and see it right here but right here they tell you how to use SMTP so for the host it will be smtp.at and paste it right here for the host then the next the port will be 465 let me copy it and paste it and then for the username let's see the username is resent so let me copy that and paste that and now for the email form this is based on your uh own email with which you have signed up so if I go back to the dashboard uh you right here see my email but I will just copy my own email right now and then pasted right here email from that looks good and now we are already done with resent we have now configured resent we have configured Google and we have configured GitHub so actually our off uh configuration object is done so what we can do now is actually go to our route. TS inside of our API folder and then pass it right here so right now we get an error since our next off function tells us expected one two three arguments but got zero and now right here we can pass our off options which are imported from our utils folder from the off file so just like that and now you see we don't get any errors anymore and that looks very very nice so now since we are done with the annoying work to set up everything we can now actually uh make everything work so let's actually now dive in and create authentication for our UI now since we want to get the session from the user and every URL we will have to create a session provider which will then pass uh to our layout so for that let me open my app folder and then inside of the app folder let's create a new folder com uh called components and then inside of the components let's create a new file called Next of um provider. TSX now right here what we have to do is on top let me import a session provider so we'll D structure session Provider from next off/ react and then what we have to do in this file is just create our own session provider provider so let's create an export const let's name it next of provider and this will be equal to an arrow function and let me open that AR function now inside of here let me just return a session provider which we have imported right here on the top s session provider and let me close that now you see we get an error and the error tells us property children is missing in type empty object but is required in type session provider props well what it tells us to make it simple is that we have to pass the children and we have to get our children through the params right here so let me destructure children right now you will now see where you'll get an error children is declared it's never read that's fine um biding element children implicitly has an any type so let's give our children and type and the type will be children of type react note now you see we don't get any errors anymore and now we can pass our children right here and you see now it works now still there's one thing missing and that's actually our session provider user State and that means that this file or this component has to hydrate on the client and right now it's marked as in server component so on the top let's just do an use client and with that we tell next shares or in that sense also react that this is in client component which has to be hydrated on the client so what we can do now is actually go to the root layout so open your Explorer let me close everything and then inside of the app folder we have our root layout and now what I have to do actually is wrap my children right here inside of the next off provider so let's first of all let me copy that let's delete it to make some space let me import my next off provider which is imported from my components and now I can uh pass my children right here again and now as you see we have now set up next off provider successfully and now actually next off works it's set up all we have to do now is create a connection between our UI with our back end uh so in that sense next off so let's go to our lockin page and actually create a connection so I'm now on my lockin page and right here we have the two buttons so we have our GitHub button and we have My Google button now how does it actually work to sign in with um Google or with GitHub or in that sense with o off and next off well it's quite easy so now to make it work with our GitHub button all you have to do is add an on click Handler and then we have to add an inline Arrow function and then we have to pass the sign in function which is imported from next of/ react and then we will have to pass our provider so in that sense this will be now the GitHub provider now let me save that uh so our development environment is running let me actually restart it just to be safe that all environment variables have been loaded so now let's wait a second so now you see our development environment is working so let me go to slash login so now this will load a second now we are on the login page or actually we are not we have an error what does it tell me eventers cannot be passed to client uh component props uh if you need interactivity consider converting part of it to a client component so again let me dumb it down a bit all it tells me right here is since you want to use an onclick Handler it must be in client component which will hydrate on the client right now our button right here is inside of a server component as you see and that's why our onclick Handler does not work so what we have to do is actually again go inside of our app folder go inside of the components folder and create a new file called GitHub signin button. TSX now inside of this file we'll mark it as use client again since we wanted to hydrate on the client now let me copy the whole G button let me um create a new function so let's do an export default function let's name it GitHub sign in button and let me open that inside of here I can now return our button so we now return a button with the GitHub icon let me now import everything so our button is imported from the components our GitHub icon is imported from Lucid react and sign in is imported from next off/ react now everything is imported and we have also marked this component as use client so now instead of this button we can just import our GitHub um lock uh GitHub sign in button component so now if I actually reload the page what do you see yes no error the page works now let's actually also do the same for our Google button so let me again go inside of the app folder inside of the components and let's create a new file called Google um signin button. TSX let's again mark it as use client and then let's export a default function let's name it um Google sign in button and let me open that function inside of you I have now to return something and for the return statement I will again just copy the button and then I will paste it right here now again we have to import the button so let me import the button let's import the image component and as you see it does not import for me so let's do the manual work so let's do an import image from next SL image so now we don't get this ER anymore and the last thing we have to do is import our Google icon so let's do an import Google icon from do/ do do/ um public and then I think it's called google. SVG so now we can go back to our login page and instead of this uh button let's import Google signin button let's also do actually already the same for our signup page and let's go to page. TSX and then right here instead of this button let's import our git top um sign in button so let's do that and let's do also the same for Google so let me delete the button and let's do in Google sign in button so now it should actually work guys so if we go back let me reload everything does it work yes can I click on sign up yes I can also click there so it should work so now let's actually test out if it works because I actually have no clue I haven't tested it out so let's do it right now let me click on GitHub since I want to test out GitHub and let's see let's see let's see okay that works so I can now authorize myself so let me click on authorize and you're being redirected I'm back on the login page well yeah of course I got redirected to the lockin page but we can actually test something out so what you can test out right now is let me open the Explorer again let's go to the page. TSX so the index page right here and now what we can do inside of this index page is actually very simple inside of this file you can get this server session so nextjs or next off I'm sorry has an very cool handy handy function called get server session this function runs completely on the server so there's no client interactivity and this makes it very safe so this right now is in server component as you see and what you can do now is right here is create a constant called session this will be equal to a wait get server session and get server session is imported from next off and then I can pass my off options and the off options are imported from our utils folder now you see we get in typescript error and it tells me arrate expressions are only allowed with an async functions so right here let's mark our um function as export default async function and now we don't get any errors anymore and what you can do now is actually right here in the H1 let me delete this hello from the index page and let's actually do an session do um user dot let me get the name why not if I now save that go back and let me go to the index page what do we see we see my name so what else can we test out let's see if we also get the image so under the H1 Let's do an image tag for the source let's use the session. user. image and if I save that and go back what you see we see my image so we see that authentication works with GitHub of course now what do we do well I think what we could do now is um I don't want that the user ever gets to this page so if the user comes to the my page and is not authenticated I want to automatically redirect the user to the login page and if the user is already logged in I want the user to be automatically redirected to the signup page so how do we do that so what I can do right here is actually do an if statement and I can check if we have no session we direct the user to the login page but if the user hasn't session Weir them to the rout slome so before I do that let me go back to my Explorer inside of the app folder let me create a new folder called home and then inside of the home folder let's create a page. TSX and then inside of here let me do an export default function let's name it homepage and then let me just open that function right now inside of here I can now return something so let's say H1 hello um authenticated user just like that so now if I go back right here I can now do my if statement so let's do an if no session is there so with an exclamation mark with that I can say if there's no session let me open that let's say return redirect now redirect this very importantly imported from next SL navigation and not from this next uh this server you will get an error if you import that from there so import that from next navigation and then inside of here let me pass actually um with strings slash login so right here we check if there's no session then redirect the user to log in and if there's in session let's do an out statement and let's do an return redirect and let's redirect the user to slome so if I now save that actually and go back you see we got redirected to /home if I try now to reach the index page so slash you see we still get redirected so you see now this works I can't reach the normal page anymore and that looks good so we see authentication fully works and we can also uh redirect the user based on the session status so now let me delete this Imports I don't need this image anymore I also don't need that button anymore and now what do we do I think the thing we could do now actually is if we go back to the login page so since the login page and also the signup pages are both server components we can again do that with the a get server side session so first of all let me delete this unused Imports which we don't need so so this GitHub icon I don't need it and now inside of our export default function I can do an const session this will be equal to await get server session which is imported from next off and then I have to pass my off options which are imported from the utils folder now we get an error again it tells me a expressions are only allowed with an async functions so let's mark this export default function as an async function now let's again do an if statement so if we have in session let's just um return redirect and redirect is imported from next SL navigation and let's redirect the user to slome so now in theory if I try to reach the lockin route so SL lockin we should get redirected to /home and that's also what you see right here let's also uh do the same functionality for sign up so let's go to the sign up page let me delete the unused Imports so I don't need that and I also don't need this icon and now again since that's an server component I can do const session and this will be equal to await get server session and get server session is imported from next off let me get the off options from our utils and again let's mark this function s a sync so now let's do the same Let's do an if statement so if there's in session let me just return redirect the user and redirect is imported from next navigation let's redirect him to m/ home so now if I try to reach the sign up page so/ sign- up you will see we'll get redirected to slome so this works perfectly so now you see authentication fully works we can authenticate the user we can redirect the user based on the session and now I think we can actually start with this fun stuff and create an actual homepage as you see right here so let's do that right now now what's the first thing we want to do I think the first thing will be a Navar so let's do that right now let's go actually to the app folder and then let's go to the components and let's create a new file called navb bar. TSX now inside of here let's do an export default function let's name it Navar and let me open that function then let's create a return statement and for now let's just do an H1 and say hello from navbar now if I go to the home page so right here page. TSX what we can do now is just return and let's import our Navar so Navar imported from our components and if I save that and go back we now see hello from Navar so so now let's actually create our Navar so yeah so to do that we will start very simple let's create a new return statement with a diff element let's give it a class name this will be W full Max width which will be 7xl MX Auto now why do we do MX Auto well that's because we actually give it in Max width and since we want to Center the Navar we have to give margin on the horizontal Side Auto auto with that it will automatically go to the center so the Navar will automatically be in the middle of the screen on the top so now what else do we need let's give it an items which will be Center let's give it in justify which will be also between then padding X which will be five then on small devices I want to have padding X of six then padding y of five and on large devices padding X of 8 and let's give it also in Flex now inside of here let's create another div element then let's give it in class name and this will will just be flex and items which will be center now inside of here I want to use the link component and in the link component I then want to uh render my logo where then the user can click to get redirected to the homepage so let's use the link component from next again this is imported from next SL link then you'll see we get an error and it tells me I have to pass an HRA property and for the HW we will just use slome since we want to link um to the homepage let's give it right in class name and this will just be width of 32 since I want to give the image which will render whts and child uh and Max width of this width 32 and width 32s if you hover over it right here 128 pixels so now inside of this link let me render the image component which is imported from next SL image then I have to pass on source and for the source we will use the logo so on the top let me import that let's do an import logo from dot do/ um do do/ public and let's see logo how is it called right here Netflix uncore logo and then for the source let me just pass the logo let's give it also an ALT which will be Netflix um logo what else do we need let's also give it in priority now why do I give it in priority that's because I want to render the logo quite fast so I want it to be rendered as one of the first things so now let's test out or let's see how it looks like yeah that looks nice the logo's uh not that big so that's good let's see on mobile device is how it looks like so I can go right here click on that and yeah this is I think that's quite all right so since we have now created the logo what I want to do now is actually uh render the links so for that let's go under the link component and let's use the UL tag right here let's give it a class name so the class name will be of LG Flex let's let's give it in gap X of four let's give it a margin left of 14 and let's say hidden so on smaller devices or mobile devices we won't see the links but when the device is bigger than large we will actually see the individual links so now we actually also have to create a few links so let's go right above the export default function and let's do in constant links which will be equal to an array so now to not make any errors let's create an interface so that we know what items to create Let's do an interface let's name it I app props and then right here we have a name which will be string and we will also have an HW which will be also string let me also maybe rename it from I app props to link props I think that's better and then right here for our links we can give it a type of Link props which will be in type array and then this will be equal to this array now now you see we don't get any errors anymore and now I can create the individual objects actually so let's do that so we'll have to create an object we will give it a name the name will be home uppercased and then we also have to give it an HW and the HW will be slome uh lowercased then the next object will be name TV shows so let's say TV shows and then for the h let's just say right here slash home slash shows then the next object which we will create will be name let's say um movies and then for the HW let's just say slome slash movies and then the next object which we will have is recently added so let's give it a name of recently added and then let's give it also an HRA and the HRA will be slome SL recently also I will urge you right now to spell that correctly corly because if you don't spell uh these words correctly you'll later on get errors so either go to my GitHub and copy it or make sure that you spell it correctly now the next object which we will use is my list since I also want to have my um list where I can create my own favorites so let's give it a name which will be my um list and let's also give it an H which will be /home SL user /list so now we have created our links so what we can do now is inside of our UL map over our links so let's do that let's get our links let's do in dot map let's get uh link and let's also get an idx and let's return that so now inside of this return statement let's create a diff element let's give it in key and the key will be an idx and then why do we do that first of all if you map over something you always have to give it a key um iterator if you don't do that you will get hydration warnings and you of course don't want to get that what I want to do now is actually uh do a very simple thing so what I want to do is later on in the URL if we're for example on the URL right here slh home/ shows I want the uh URL which is equal to this URL or this H in that sense to have for example a white underline and if it's not equal I want to make it a bit grayish so it's uh different so it's opposite to each other so you definitely can see okay this link is currently active and this one is not and for that what we'll use is actually the path name and then with the path name we can check if the H is equal to the path name so to do that it's very simple we'll have to use an um hook provided by next so let's create a constant called path name which will be equal to use path name this is now uh imported from next SL navigation and again since that's in hook um this file or this component has to hydrate on the client so on top let's mark it as use client so that looks good and now what I can do again inside of this div is actually check this path name so now right here you can do path name and if this will be equal to link. hre let's use annary so question mark let's return something and if it this is false let's use some colon and return something else so now for now if it's true let's create an Li tag and inside of the LI let me use the link component U from nextjs now we'll have to give it an H so for the hre this will be link. hre let me also give it for now a class name which will be just text white to see it and then for the name let's just use link. name and now if this is not true let's use uh let's do the same so let's use the LI tag and then inside of here we will use the link component and we'll have to give it an HRA so let's do an hre which will be equal to link. H and for the name let's just do an link. name if I now save that and go back you now see each link but now you still don't see what I already explained what I wanted to do so when the link is active I want uh the home uh page for example to have an underline so let's do that right now so inside of here where we check if the link is equal to the HW let's give it a few more class names so we have text wide let's do in font which will be semi Boldt let's give it an underline and a text of small if I now save that and go back you now clearly see which link is active since the home uh link right here has an underline is and has a different font uh to the other links uh maybe I can zoom in a bit more so that you see it even better now let's do the same also for the link uh if it's not true let's also style it so let's give the link a CL T name and let's give it in text which will be gray of 300 font which will be normal and text which will be also small if I now save it and go back you now see this looks way better the font is now um almost uh similar and the size of the text is also similar so this now looks better and I really like it actually so we are now done with the links actually and what I want to do now is on the right side if you can remember we had in search icon a bell icon and a user um navigation button where the user could click and then lock out so let's create that right now so to do that that's again very simple we will just go above the last diff right here and then we will create a new diff element let me give it a class name which will be Flex We will have items which will be Center gap which will be X of8 and then inside of here I want to use my Lucid react um SVG icon so let's let's use the search icon that's imported from lo- react and let's actually see how it looks like yeah you have an icon right here I think that's too big actually so let's give it in class name this will be W of 5 height of 5 text which will be gray of 300 and let's just do cursor pointer even though this button won't work since I won't create the functionality for it but now you see yeah this looks uh actually way better so I think that's good then the next button which we'll have is the Bell icon so let's search for Bell I will import that from Lucid react let's again give it a few class names so height five width five let's say a text of gray 300 and let's do a cursor which will be pointer so if I save that again and go back yeah that that looks quite nice now the next uh step which we want to do is create the user navigation and this will now be a a bit more complicated than just the two icons but still I think it's possible to make it so let's do that right now so what we have to do right now let go inside of our app folder inside of components and create a new file called user um na. TSX now to make the user navigation work we will actually now have to go to shaten UI and install a few things so right now let's first of all search for Avatar since we will need an avatar so that's right here so let me go to the CLI and let's copy it and then let me open my terminal right here again let's paste it and let's install the Avatar so what else do I need I think the last thing uh which I will right here need is the drop down menu so again if you can remember we had the Avatar and if I click on the Avatar we will open a drop- down menu just like here so let me go to the CLI let me copy the um installation command let's paste it right here this will now install the drop- down menu so that looks looks good so let's wait let's wait and let me again also restart my def server with npm1 Def and then let's actually create our user navigation so let's do an export default function um let's name it user nav and let me open that function now inside of here let's create a return statement and first of all let's get the drop- down menu which is imported from the components now again you should be quite certain that you import that from components are not from RX since we want to have the styled variant and not just the default RX component so let me import that so what else do we need um we need the dropdown menu um trigger this is again imported from components then let me uh open that this will be know as child then inside of here I want to render a button this is imported from the components then let's give it in variant the variant will be right here ghost then let's give it a class name and the class name will be relative let's give it an height of 10 width of 10 um let's also give it in rounded which will be small then inside of here I want to render a avatar so let's import avatar from components let me open that and let's give it a class name the class name will be um height of 10 and width of 10 and rounded will be the same of small then inside of here I can now give it an avatar image and right now we actually won't get an avatar image but still let's import that from our components and this is in self closing tag and for now we will leave it empty but of course we will uh later on add something then as an fallback Let's do an avatar fallback this is imported from the components and that's given in class name the class name will be rounded of small and let's give it a name of I don't know Jan so now let's actually see if it works so you can go to your nav bar and import that so under the Bell let's import our user nav from our user nav file so if I now save that and go to local 3000 well what do you see you see now the usern nav right here if I now click on it you see nothing happens but still you right here now see our usern nav so now where we see that this um user navigation actually works let's now actually create the avatar image now you'll see right here that we have to pass in Source now we can just pass a normal image how we would do it normally with for example the next component we will actually have to pass an URL that means we have to host our user image somewhere and for that we will again actually use super base so let's go to super base so I'm now in my super base dashboard now let's go right here to storage let's create a new bucket let's name it just user image let's make it a public bucket and let me click on save this will take a second and now what do you want to upload here well actually if you again open my Explorer and click on public um right here we have an avatar.png what I want you to do now is go to superbase and upload this image so let me do that real quick so now you see I've uploaded this Avatar image and what I can do now is actually get the URL right here so let me get the URL and then if I go back to the usern Naf I can pass it right here for the source if I now save that and go back so now you see our usern knife button works but still if I click on this button nothing happens so now let's actually create this whole um drop- down menu content field so for that let's go right uh below this drop-down menu trigger and just above the drop- down menu and let's get the dropdown menu content this is imported from our components and not from redx UI let's give it in class name which will be width of 56 and then let's give it also an align prop and this will be end and let's say Force Mount then what else do we need we will need a drop- down uh menu label this is again imported from the components inside of here let's now just create a diff and let's give it in class name this will be Flex Flex which will be call and space y of one then inside of here we want to create a P tag and let's just just say I don't know my name Jan for now and let's create a pag with let's just say just some jish email.com if I now Sav that and go back you can now click on uh this user right here and we now have this drop down as you see which looks quite nice we have a name and some jabush email now let's actually also style that since that still does not look perfect so let's give the PC a class name which will be text of um small let's give a font which will be medium let's say a leading which will be none and I think that's fine then for the P tag let me also give it a class name which will be of text XL leading which will be none and let's say text which will be muted and foreground if I now save that and go back and click on it yeah you see this looks very nice now the last thing which I need is uh the lockout button so let's create that for that we will go under this drop down menu label and create a drop-down menu separator and this will now be again imported from the components and this is a self closing tab and if I save that you'll right here now see the small little border and what do I want to do now under the drop down menu separator let me create a new drop-down menu item this is again imported from our components and then inside of here let's say sign out if I now save that and go back you now see the sign out button right here what you can do right now is actually also add an onclick Handler since we of course want to make it work so let's do an onclick uh let's use an inline Arrow function and let's call our sign out function which is imported from next off react but now still this won't work why because right here we use an onclick Handler but our usern n file is not marked as used client that means if I now click on this button nothing happens so what you want to do is Mark this file as use client on top so let me do that use client and if I now save that and go back let's test it out I will click on sign out and you see we get redirected so sign out I you sure you want to sign out yeah let's sign out but now even though we have signed out you still see we are still on the homepage and we of course don't want that to happen what we want to do is if the user has signed out we want to redirect them to the lockin page so what we have to do is actually very simple again let's open our app folder let's go to the home folder and let's create a new file called layout. TSX so again what do we have to do we have to do an export default function let's name it home um layout and let me open that function then inside of here I will want to render my children since this is a layout so we have to render the children right here and we have to get the children through the par so let's D structure children and this will be of type so let's do children of type react note this is imported from react and now we can use again our use server uh get server side session hook and with that we can get the session so let's do in const session this will be equal to8 get server session which is imported from next off let's pass the off options from our utils also right here you see we get an error it tells me that I have to mark this export default function as async so let's do that export default async function and now we can do an if statement so if there's no session let's redirect to/ login so let's do an if no session is uh there let's do in return redirect redirect is imported from next SL navigation and let's redirect to/ login if I save that let's reload everything let's see you see we'll get redirected I can again click on lock in with GitHub so let me do that right now I will now get redirected to slome you see right here we get an error it tells me objects are not valid as react a child found object with keys children so if I go to layout yeah that's the error it returns children as an object that's of course not correct so let's do in return let's do in diff element and then we can uh wrap our children right here so if I save that and reload everything you now see we don't get any errors anymore I can now again click on sign out we should now get redirected to/ login let me again loog in with GitHub and it works perfectly that's nice now there's one thing you should know if I would now click on Google and with log in with the same email as GitHub we will get an error it won't work so um with next off it does not automatically link accounts so that's why you have to if you want to use Google and uh GitHub at the same time you have to use different email providers so now let me actually test out Google I will click on that we should get redirected to Google and you see nothing happens that's because if I go to the Google sign and button component you see nothing happens that's because we have no onclick Handler so let's create a onclick Handler let's make it an inline Arrow function and let's say sign in sign in is imported from next off react and let's say Google if I now save that and go back and if I now click on Google you will see we will get redirected to the Google signin page and now I will choose a different account than what I have with GitHub so a different email let me choose this one right here and now let's see we should get redirected and yes we're at slome I can again click on this and click on sign out and we get signed out so you see o off now finally works so currently the email off won't work and why is that that's because if I go to my EnV right now I have here my own email that's incorrect it won't work that's because we are in test mode so what you have to do is if you go to the resent docs in test mode you have to use their own onboarding at resent dode uh URL so if I now paste it to email from this will now work also another thing is you can just now paste any email inside of here since we're in test mode you can only send an email to your own email with which you have created your recent account so yeah you can just uh put paste any email you will have to put the email inside of here which you have used um to actually create your account but now um let's actually restart our Dev server let me clear everything let's do npm1 Dev this will restart everything and again to summarize now instead of email form where you put your own personal email put right here onboarding at recent. Def and then for the email login input you can now put your own personal email with which you have created your recent account now let's see if our death service again running um nope so let's wait for that so now let's actually test it out I will now just write some DB gibberish email since we'll get an error I already know that so let's do test at gmail.com and what has happened well actually nothing has happened we now just seen the URL we uh have made an get request because in the URL I see Emil is equal to test gmail.com and that's not what we want we want to create a post request and it's actually very simple why it does not work it's because we have to actually also submit our form currently our form is just a normal get request and we want to make it in post request so how does it work let's go to our lockin route let me first of all close everything and let me go to login so to the login page and now right here in the form you see we just do nothing adjust and form which automatically doesn't get request so what we want to do is give it in method and the method will be post and then we also have to pass an action and for the action we'll have to pass an URL and the URL will be SL API slof slash sign in with that we will now actually um create a action where the user can then sign in with the email let's do the same also for the sign up um page so let me go to sign up that that's right here and let me do the same for the form I will just paste it so method post and the action which is API off sign in if I now save that and go back let me reload everything to make sure that everything works and now let's uh let me make my actual email so let's do that and if I click on log in and then you'll see we'll get redirected to the own next off website where I can now again put my email inside so let me do that and if I now click on sign in with email I will now get a magic link sent to my email so let me open my email inbox so what do you see now you see I got an email with sign in to Locos 3000 where I can sign in so let me click on the sign in button I will get again redirected as you see and I got redirected to /home so you see this works perfectly now our o off completely works so Google and GitHub and also email authentication also works this is great and I think we can now actually create the fun stuff and that's right here Netflix so let's do that so there's right now one thing I would like to change So currently our nav bar is rendered inside of the page. TSX so for the index page of our home route but if I would now create a sub route in my home folder so let's say slome SL ABC I wouldn't render the Navar anymore and that's because right here render the Navar not in a layout but in a page. TSX so what I would want to do right now is go right here inside of my layout. TSX where I check my session status and redirect the user based on it and then inside of here I would like to render my Navar bar so to get started let me delete this old return statement since I want to create a new return statement let's use right here empty brackets and they are just an alternative for diff uh tags the only difference is they don't show up in the Dom but uh diff elements for example show up in the Dom then inside of here I want to render my nav bar let me import that from our components and if I now go to this page. TSX and instead of this nav bar let's just return right here a H1 and let's say hello from um home save that and go back um let's see does it reload for me yes and you see it looks the same we still have the nav bar and that looks good now if you wonder why you don't see this H1 tag right here hello from home that's because we don't render the children in our layout so right now if we go back to our layout you see we just rendered the nav bar but not the children and that means in this context right here our layout. TSX takes the roll of the page. TSX and overshadows it uh if you want to um think of it like that so what we want to do is now render our children and for that let's create a main element and let's also give it a class name since I want it to have the same padding as our nav bar so let's give it in W or full or let's first of all give it in CL last name of w full Max width which will be 7xl MX Auto since I want to Center our Navar uh let's give it a small which will be padding X of six and LG which will be padding X of 8 and now inside of here I want to random my children so let's get the children right here if I now save that and go back you now see hello from home and the nice thing that you also see is that the padding um from the Navar and from the H1 is the same so that's what I did with the main element right here so now with that's out of the way I think we can now actually create um right here the index page with the movie player and the individual movies so let's do that so to get started let's create the movie video so right here on the index page the playing movie and for that let's go uh let's close everything let's go in the app folder in the components folder and let's create a new component called movie um video. TSX and now right here I of course want to render a a video and we have to get the video from somewhere well now there are a few options and I already thought about them before I created this video what could we use um I played first of all around with tmdb and API and then I came to the realization well it does not work so good as I want to it's of course better to be your own source with your own videos so what we'll do is fetch the movies from our own database and for that of course we first of all have to fill our database with actual movies so now in my schema I want to create two models so first of all a movie model and a watch list model with the movie model I want to store movies but not only movies but also TV shows for example or um movies in that sense and then what else do I want I want to have a model which is watch list and with the watch list I want to store the users watch list so what movies the user favorites now it's very important that you spell everything correctly inside of the schema and if you want to be sure that you spell it correctly you can go to my GitHub right here click on Prisma folder then click on the schema file right here and then you have the two models right here model movie and model watch list so now either follow me and be quite sure that you do everything as I do or go to my GitHub and copy it from there but now what I want to do is right here create a model which is called movie Let's Open that then let's give it an ID which will be of int and let's give it an ADD ID and I won't give it any defaults to generate a ID for me and that's because I will actually pass the ID myself when I push the movies to my database then the next field I want is the image string and with that I will just store my image as in string then I want to have an title which will be also a string then we will have an age so at what age is the movie recommended at this will be a integer then what else do we need we need a duration and now I will give the duration a float and not a int that's because I want to have the duration as a decimal number and not as a normal integer then we'll also have an overview or in that sense a description this will be also of typ string then we'll have a release date and the release date will be an integer then what else do I want I want to get a video Source this will be also of type string and then let's also get the category so in that sense we will have multiple categories so a movies category a TV shows category a recently added category for example then this will be of type string and let's also do a YouTube string and the YouTube String will be of course of type string then the last thing I want is the created ad timestamp and with that I can then later on sort my movies based on the created ad timestamp so let's do a created ad um this will be of type daytime and let's give it in default with now and with that I tell my um database to every time generate a new timestamp when I insert a new record and now the next model which I want to create is the watch list model so let's do a model let's call it um watch list let me open that let's give it an ID which will be string this will be an at ID at default and uu ID with that I tell my database hey every time when I create a new record I generate a new unique identifier form me on the default then I want to start the user ID with that I can then reference uh which watch list um belongs to which user and then the last thing I of course want to do is create a relationship so I want to create a relationship between movie and between watch list and for that of course you have multiple options or there are multiple relation types so there's a one to one relationship there's a one to many relationship and there's a many to many relationship now if you think about it we have a movie and we have a watch list and we have a user what relationship do you have to generate between movie and watch list well it's quite simple we have one movie and one movie can have multiple watch lists but each watch list can only have one movie so in that sense we want to generate a one to many relationship so to do that that's actually quite simple so what we have to do inside of the movie uh model right here is let's create a new field called watch lists and this will be of type watch list as an array with that I just uh create a relationship and say hey movie I want you have a relationship with watch lists and watch lists is an array and in that sense I want to have an one to menu relationship if I now save that it will actually generate everything for me as you see right here and we have now created a nice uh relationship and one important thing is if you want to have the same Auto generation you have to have the Prisma extension so if you click right here inside of the extensions table um you can click uh search for Prisma and then right here install that that's very important but with that out of the way we have now created the schema and again I want to urge you please double triple check that everything is spelled correctly because I you don't want to get any errors I will also check it right now and then um I will come back so after double checking it seems like I've not misspelled anything which is very nice so what I can do right now is actually push my schema to our uh database at super base since right now our both the schemas are not in sync so our schema right here with Prisma or in our local environment in that sense is not in sync with our production database at super base so let me open my terminal let me stop my def server and also right here you see a few warnings because of next off this is not important for us we will fix These Warnings as we will um actually deploy our application to our cell so right now it is no concern for us so let me clear everything and then I what I want to do is an npx Prisma DB push since I want to push my schema to my um post Quest database so you now you see our schema sign sync so let's do npx Prisma generate um just to generate our new Prisma client so now where our database is actually created or the models in that sense we of course also have to seat our database since right now our models is completely empty so what I want you to do is actually go to my GitHub since if you go to my GitHub and check the seat folder inside of the app folder we will have an file called page. TSX and all this is is actually just in server action where I seat my database so as you see I write here call create menu and then I just SE my database so what we have to do now is go inside of the app folder create a new folder called seat and then inside of here let's do an page. TSX now we actually just created a new routee but that's all right then inside of here let's do an export default function and let's give it a name let's just name it seed um database and then let me open this function right here now this will be a very simple route all we need to do right here is just doing return statement we will return a diff element let's give it a bit of margin so let's give the class name of margin five inside of here I will use the normal form element um let's delete the action for now and then inside of here let me just use the button component from our components and let's say submit I will have to give it in type since I want to submit the form so let's give it in submit type what we have to do now is create a server action so we can give our form a action so right above our return statement let's create a async function let's name it post data and let me open that function so right now this is just an async function which runs on the client so let's give it an use server keyword to mark it as an server action and now to actually seat our database we of course need the movies so let me go back to my GitHub and let me just copy this whole constant data a wait pisma movie create manyu so to create multiple movies so I will copy this whole um function let me copy it and then let's paste it inside of here again what do I do here all I do is if I scroll up I create a constant data this actually not needed let's just arate then Prisma movie I create many movies then I have in data um which is an aray with multiple objects as you see and then each objects corresponds with our schema uh model which is called right here movie so each type is also present right here we have an ID a title an age a duration which is in float as you see a overview a video Source image string release date category and a YouTube String now right here I have to import pisma so let's import that from our utils and now that looks good now the only thing I have to do is connect my server action with my form so let's give it an action and this will be called post data now we have created our seat file so if I return back to my def server let's go to the route seat as you see right here/ seat I get an error and that's because my def server is not running so if I open my terminal and run clear and then do a npm run Dev let me restart my def server and let's go back so now I'm on/ seed and as you see I have now my button so let me just click on it this will take a few seconds let's wait for that and now I can again open my terminal right here let me uh go to my second terminal Tab and then inside of here let me clear everything and let's do an npx Prisma studio with that I open the Prisma Studio this will now open low close 5,555 um this takes a second for for me let's wait and now you see Prisma studio and right here have my movie uh model and now inside of here you see I have 11 records so 0 to 10 um that looks nice and you see everything is also added and that looks very nice so now our schema or our um database is actually seed we can continue let me stop my um PMA Studio I don't need it and let me go back to my tab and now what can we do we can create our movie um player this movie video right here the component so let's do that right now so now to get started I think the first thing I want to do is first of all a export default function let's name it movie um video and let me open that function inside of here first of all let's just return a H1 and let's say hello and then of course if I now go back to loc CL 3000 so I will go back this takes a second let's see let's see let's see you you see right now just hello from home and that's because my component right now is not imported anywhere it's just a component which is empty so what I want to do is actually right now let's open the Explorer let's go inside of the app folder inside of the home folder and inside of the page. TSX and then instead of returning this H1 let me return my movie video component if I now save that you can now see right here hello that looks nice so now let's actually continue what's the first thing I want to do I think what we should now do is actually first of all fetch our data so Above This export default function right now let's create a new function a new async function so let's do async function um get data and let me open that function inside of here I want to now query my database and just find the first record in my database so let's do that actually let's create a constant called Data Let's do an await Prisma Prisma is imported from the utils folder um movie and I want to find the first so right here we have an cool helper method which is find first now right here I don't want to actually fetch the whole movie since if I open right now my movie uh my schema and then if I go to my movie model right here you see a lot of stuff we have a created ad uh tag a category tag I don't need that I just need the title the duration the video Source Etc so what I can do now inside of this fetch call is doent Select and then select everything I need so I need a title so let's do true I need a overview so let's do set it to true I need a video Source let's set it to true then I need a image string let's also set it to true then I need a release date so let's set it to true I need a duration let's set it to true and a ID so let's set it to true and the last thing I need is the H or the recommend mended age so let's set it to True with that I've now selected all the fields I want from my movie model and with that I don't fetch the whole movie model and with that I can also save a bit of compute time and bandwidth so now the last thing we have to do is return that data and now let's get it on the front end and for that all we have to do is s cons data Let's do an equal arrate get data and now you see we get an error so if I hover it um ARR expressions are only allowed with an async functions at the top level of modules did you mean to mark this function as async well yes so let's do an export default async function so now we have created an server component with which refetch data and now I get the data right here so now we can actually start with the fun stuff and actually return something let me delete this old return statement and let's do a new return statement let's create a diff element let's give it in class name and I want to give it an height and I want to use and custom height so for that I will use array brackets as you see right here then let's give it an height of 55 viewport height so 55% of the total screen uh height real estate then for larger devices so LG and more I want to give it an height of um 60 viewport height so again a custom value 60% of the total height then let's give it an W or full let's give it in Flex a justify of Center and let's say items also Center so I Center the children of the stiff now inside of the stiff I want to play the video so for that we can use the HTML video tag as you see right here and we have now a few options which we have to pass inside of here so if I make a bit of space the first property which we have is the poster property and the poster property you can think of it like a thumbnail so before the video loads we will see this poster so let's give it a data do image string that will be our thumbnail then the next property will be autoplay so the uh video will play automatically then let's make it muted so no sound and let's say a loop then let's also give it in Source since we of course need a video source and this will be data. video Source there's one more thing which we need that's a class name since I want to also style this video so let's go it in W or full let's say absolute a top of zero a left of zero let's also give it in height this will again be custom value of 60 viewport height so 60% let's say object which will be cover and now I think we can save it and see how it looks like so if I go back um well you see the movie as you see here and if you reload the movie you will see for a split second a thumbnail and then the video starts to play so that's the thumbnail which I just talked about or how they name it right here poster now there's currently one thing I don't like and that's our video overlaps our nav bar So currently our video is absolute positioned and that means that our video currently overlaps our Navar and to change that we can use the Z index and then right here we can give it a minus Z of 10 and if I save it and go back you now see that the Nava is over the video but still you see both which is quite nice now there's currently one more thing our video right now is quite bright as you see and we have contrast is shoes with our NAB so what you can do right now is give it in brightness so brightness scale and now I want to set my brightness again to a custom value so let's use the array brackets and let's say 60% if I save that again and go back you now see the video is much darker and the contrast between the Naf bar and the video is much better so our Naf bar is much more visible that looks very nice so now uh I think what we will do is actually create the H1 so so the title of the movie a little description of the movie and two buttons so let's do that right now so under this video tag I want to create a new div element then let's give it a class name which will be absolute then for the width I want to use a custom width so 90% And then for larger devices let's do a width of 40% and then let's also do an MX Auto to Center the children inside of here I can now R the a H1 tag with the title so letu data. title if I now save that and go back you should now see in a second if I reload the page yeah right here you now see the title Grand Turismo now this does not look nice but I will fix that in a second so now let's actually style our H1 tag for now let's give it a class name of text white let's do text which will be 4 XL medium which will be text of 5 XL um LG so large devices text of 6 XL and a font which will be bolt then for the name I already give it gave it in title that's nice let's also right now use in pag to render our description so let's do in data do um how is it called overview and then for the class name let's give it a class name of text white text which will be large and margin top of five if I now save that and go back you now see the title and the description or the overview in that sense one thing you could now do also is add a line clamp to the description so let's do an line clamp or free and with that I limit the overview to be maximum of three lines as you see right here now the last thing I want to do is add um two buttons actually so one button to see uh the video and one button to learn more to do that I will go under the pag right here and create a new diff element then let's go the class name of flex Gap X which will be three and margin top of four inside of here I want to now render two buttons so let's use the button component let me import that and for now let's just say cm more and then let's render another button and let's for now just say um learn more so now you see our title our description and the two buttons now even though that looks fine one thing I don't like is that it's centered and if I go back that's because I gave it right here justify Center and with that I of course Center my um children but in that case I don't want to Center them what I want to do is actually put them to the start so let's do a justify of start and if I save it you see this looks already way better now one thing you of course see right now the text is very big and the buttons are very near to the bottom that's because my screen is very zoomed in but in the normal case when you use 100% you see this looks uh way better but for you it's a bit too small that's why I have to zoom in for you for you but still that looks very nice now the buttons of course are not styled and don't look good but I will change them later on when we actually add the interactivity for for them since right now they are only buttons but now one thing we can check is how does it look on mobile so if I make it a smaller device one thing you would see right here is it right here actually touches the Border or the corner of the screen in that sense I don't want that so what you can do for that is right now go to your page. TSX inside of the home folder so right here and then instead of just rendering the movie video Let's actually render a diff element with u the movie video as a child and then let's style our diff element and let's give it a class name of padding five and on larger devices I don't want to have any padding so pending zero if I save that and go back and make the screen again a bit smaller so a mobile device screen you see now it does not touch the screen and this looks very nice in my opinion so with that out of the way now let's actually create two movie t right here at the bottom so a recently added movie uh Tab and a um I guess my watch list um tab so to do that let's create a H1 tag under this movie video let's say um recently edit and let's give it also a class name which will be text or fre XL font which will be Boldt and I think that's fine if I now save that U TC recently added and what I want to do now is render the videos which were recently uh rendered and for that we will actually create a new component so let's go inside of the um app folder inside of the components folder and let's create a new component called recently added. TSX so I'm now inside of the Recently Added component and the first thing that we have to do is the same as always let's create a export default function let's name it recently edit and let me open that function inside of here let's do a return statement and let's say A P tag and let's say hello from the component if I now save that and go back and reload the page you of course see nothing and that's because our component is currently not hooked up to this route so let's go inside of the home folder and inside of the page. TSX and then under the H1 tag let's import our recently added component this is again a self closing tag let's save that and right here now you see recently added and hello from the component so now we can fetch the data and then show the movies so let's do that so before we do any UI stuff we of course have to fetch our data so above the export default function Let's do an async function let's call it get data and let me open that function inside of here I want to now fetch the most recent movies and I will actually sort them by the created update to again get the most recent ones and I will also so limit the maximum items to four so I only want to get four movies from my database so let's do that so let's create a constant let's call a data this will be equal to aate Prisma prisma's imported from our util folder movie doind many since I want to find many movies now inside of here I want to again select a few things I don't want to fetch the whole movie but I only want to fetch a certain part of the movie and with this I again reduce the compute time and also a bit of the bandwidth so let's do a select and what do I want I want the ID so let's set that to true I want the overview let's set that to True let's get the title let's set that to True let's get the watch lists let's set that to true and let's get the image string let's set that to true and let's get the video source and we will set this also to true now again I want to order these um items since I only want to get the most recent ones so let's do order bu and then we want to get a created ad Tim stamp and we want to make a descending since we want to get the most recent date and therefore we have to do it as descending and not ascending and again if you can remember I only want to get four items back so we can use the take property and we will only take four items now we have written our fetch call so now we can return our data which we fetch in the front end we can now do a constant data which will be equal to await get data now you see if I hover over await I get an eror await expressions are only allowed within Asing functions at the top level of modules that means we have to mark our function s a sync and now you see we don't get any errors anymore so now we can actually start so let me delete this old return statement let me create a new return statement and let's start off with a diff I first of all have to give it a few class names so let's do a grit because if you again can remember on on larger devices I want to have a grid of four items but of course if we are on smaller devices there isn't enough of there isn't enough size to show all four um images or all four movies horizontally that's why when we on smaller devices I only want to show them in a column of one if we on a bit of bigger devices so for example small or medium devices I want to show two or three columns and if we are on large devices so right now on a MacBook or on any computer we want to show four column so all four movies horizontally so now let's take this theoretic stuff and put it into practice so if we on a small screen let's make grid calls one if we are on a smaller screen so SM and above let's do grid calls of two if we on a medium device or above let's do a grid um calls or free and if we on a large device let's do LG grid calls of four now the last thing I want to do is give it some margin on top so let's do margin top of eight and I of course want to do a bit of gap between the movies so let's do a gap of six Let Me Now map over our movies inside of here so let's do a data do map let's get a movie and let me just return that now inside of here let me render a diff element we of course have to give it in key um to prevent any hydration warnings and we'll give it in movie.id and let's give it a class name of relative and height which will be 48 48 if you hover over it you see that's 192 pixels and now inside of here let's render our image so let's use the image component uh imported from next image inside of here we have to pass a source for the source this will just be movie. image string then we need a um alt tag for the alt tag we would say movie Let's also give it in class name which will be rounded of small um let's also do a absolute let's let's do a width of full and let's do a height of full if I now save that and go back and we load everything let's see and we get an eror image la la la is missing required width property so we have to give our image a width and height property so let's do width of 500 and let's do a height of 400 if I now save that and go back let's see uh our invalid Source prop on on next image host name image. tmdb is not configured under your images and next config so let's actually do that to do that let's go to our next. config.js right here and again why do I have to do that well if you fetch um images from a remote data source so in that sense right here from tmdb we have to actually tell next shares hey these images come from this URL so right here you can optimize this images and if they're not coming from this URL that means that this is probably a malicious attack and those images are not for me so I'm hey don't optimize them only optimize the images which come from this certain um host name so to do that you can follow this thing right here let's copy that and let's paste it in a new tab to see what next shares tells us and what does it tell us right here possible ways to fix it add a protocol host name port and path name to the images um images. remote patterns config and next config.js so let's actually do that let's go back and then inside of this object we have to get our images then let's open that inside of here we have remote patterns this is an aray where we can have multiple objects since we can have multiple remote addresses then inside of here let's create a object let's give it an protocol the protocol will be https then we will have a host name and for the host name you can go back to your def server and then you see it right here image. TM db. org let me copy that and paste that and then the last thing we need is the port and for the port I will just give it an empty string so now that looks good if you open your terminal right here let me stop my def server even though it restarts automatically I just want to be safe so let me stop it let's clear everything and let's do npm1 def this will now restart my def server let's wait for a second to restart so now you see my def server has restarted and now we see everything we see right here our title and the four movies right here now still as you see they don't really look good so for example right now they have their own object size and what I want to do is make the images cover our certain size so that they have a correct aspect ratio to do that let's go to a recently added component and for the class name let's do a object which will be cover if I save that angle back you see now that the aspect ratio is correct and that looks way better so now what I want want to do is if I hover over the movie I want to get more data about it so in that sense the title a small overview the age restriction Etc so let's actually do that so under our image component let me create a new diff element let's give it in class name of height 60 um let's do relative set of 10 so if I hover on the image I want this hover overlay to overlap our image right here as you see then and let's give it in W or full let's give it in transform then I want to have in transition let's also give it in duration which will be 500 milliseconds and a hover which will be scale of 1 to5 so 125% let me also give it an opacity so when we don't hover or on it I want to have an opacity of zero so the user does not see it but if the user hovers over the video or on the movie I of course want to show the uh overlay so lets you a hover of opacity 100% so now that looks fine now inside of this div um I can now render actually the image again so let's use the image component and we have already imported that let's give it the source The Source will again be the movie. image string then let's give it an ALT which will again be the movie we'll have to give it an width which will be 800 let's give it an height which will also be 800 let's also give it now a class name and the class name will be absolute um width of full AG of full um minus Z of 10 and that's you rounded which will be LG and a object which will be cover if I now save that and go back let's see how that looks so I now hover on each image and you see this little overlay right here that looks quite nice in my opinion what I want to do now is actually now render the text so the title description and the play button as I already said and for that I will create a separate component since we'll use it for multiple and Pages actually so let's go again in the app folder components folder and let's create a new component called movie card. TSX let's do a export function let's say movie card and let me open that function inside of here let's do in return statement and let's return for now a H1 and let's say hello from movie card if I now save that and go back we can now actually import our component under our image so let's import movie card um right here let's save that let's go back and if I now hover on each movie you see on the top left corner our hello from movie card that looks all right but now there's one thing if I hover over this movie right here you see our text is right and the image is quite bright that means that we don't have really a contrast and you can't really see the text so for that what we have to do is actually wrap our image in another diff and then actually lower the brightness so make it so give it in dark overlay so what I will do now is copy this movie card and image then wrap it inside of a diff element and now let me style this diff element so let's give it a class name which will be BG of gradient m- 2-bottom so I want to have in gradient to the bottom then let's do from transparent so on the top I want it to be transparent via let's say black and let's give it an opacity of 50% with the slash to normal black 100 then let's give it an set of 10 and let's do an width of full a height of full a rounded which will be LG a flex items which will be Center and a justify which will be also Center if I now save that and go back and if I now hover on each image you now see that the text is centered we see now this gradient from the top to the bottom where on the bottom we have this more darkish color and on the top we have a transparent color we see that the image is um actually rounded so that looks nice one more thing we can do is add a border to just see it a bit better and if I go back yeah I think that looks quite nice actually so now everything is centered we have this uh gradient I think we can now actually come back to the movie card and now render the title and everything else so for that I will actually create a interface since we will need a few things so what I will do is on top create a interface inside of the movie card and let's name it I app um props and let me open that inside of here I want to get a few things so I will want to get a title which will be of type string I will want to get an overview which will be of type string I will want to get a movie ID which will be of type string I will want to get a watch list which will be of type Boolean and with the this I will then later just check hey has the user added this movie to the watch list if so I will set the Boolean to true if not then false then I will have a watch um list ID which will be of string and we will need this later on to delete our movies from the watch list and let's get a YouTube um URL which will say string so that the user then can uh click on the movie and actually see the trailer so now I want to get this items through my params so let's the structure and give it the type of I app props inside of here I can now click actually on control space bar and you see that we get all of these items so let's get the movie ID again the overview the title the watch list ID the watch list and let's get the YouTuber URL if I now go back to the Recently Added uh page right here you now see I get an error if I click on movie card and it tells me right here if I hover over it um type empty object is missing the following properties from I props title overview movie ID watch list and two more so all it tells me in basic terms is hey you have to add these properties please do that uh because if you don't do it movie card won't work as you want to so let's do that and let's follow the request so let's give it a movie ID this will be of type a movie. ID then we will have a overview this will be of movie do how is it called right here overview and then right here you see right now I get an error and it tells me type number is not assignable to type string so what's the error in movie card I told my I props right here hey I want to get a movie ID and I expect it's a type string that's incorrect the type should not be string but it should be type number and if I now save that and go back you see this error has now gone since the type movie ID is coherent with the type that I have added right here in my I app props so what's the other properties we need the title this will be of type movie. title what else we have a watch list ID now right here for watch list ID um we actually if you hover over data you see we get in watch lists array back but I already know that we only get one item inside of the watch lists array that means what I can do actually is get the movie. watch lists I can get the first item with this array brackets zero and then I can get the dot ID if I wouldn't add the zero with an array so I can delete that you see I get an error because it thinks or it not thinks it's true uh watch this ID is in map or an array I'm sorry and with that I can't get the ID that's why I have to use an array with zero to get the first item inside of the array and then I actually know hey I can now get the items from which I want the ID then the next property is the YouTube URL and this should be of type movie. yoube and as you see I don't have it so let's check our fetch ID overview title watch list image string video Source this is incorrect I don't need the video Source but I need the YouTube String so if I go back I can now add my YouTube String then the next property which we have is the watch lists and now if you can remember again if I go to the movie card our watch list is a Boolean and with that I just know hey this movie has been added to the um watch list or no this movie hasn't been added to the watch list and to actually achieve this and give this data to the movie card I have to do inary so movie. watchlists and then inside of here let's check if the length is bigger than zero then I can set it to true and if this is false I can set it to false and again to summarize what do I do here well I check hey the watch list is in Array if the length is bigger than zero so if there's an item then I tell the movie cut I'm I know that there's a movie inside of the watch list so I can mark it as true if this is false that means if the watch list away has no items and so the length is zero I know hey there is no movie inside of this watch list so let's set it to fults that's all we do right here and then we can also add a key and the key will be movie.id so now we have added all of our properties to the movie card and we can now continue with the movie card actually so inside of here let me delete this old return statement let me use these brackets right here and then let me create a button but a normal button now not the normal button which we use um let me uh use our Lucid react icons so let me search for play circle let me import that let me also give it a class name and this will be of height 20 width 20 and then for our button let me also style it let's give it a class name of margin top of 14 so if I now save this angle back we get an error cannot read properties of undefined reading ID and well the problem is that that we have to add a question mark right here and why the question mark because the watch list ID can be empty so our watch list can have no items and that's why our ID can also be undefined if I add this question mark I now uh tell our react code hey I'm not sure if the ID exists it could be defined it could be undefined and now we get also an error right here um type la la la la la uh void is not valid jsx element type so the error is right here I have not created an return statement dumb Mistake by me so let's do a return and let me again paste the code so if I now save that and go back and let me also save the Recently Added component so now I can go back to Chrome um reload everything and now you see if I hover over the images or over the movies I get right here the overlay and display button but if I click on it of course nothing works right now but I will fix that so now what else do we do I think we could now actually render our watch list or this icon so if the user has favorited the movie I can show a red icon or Red Heart icon and if not then not so under the button let's create a diff element let's do a class name of right five top which will be also five a absolute positioning and let's do a z of 10 now inside of here I can now use my watch list Boolean so again if you can remember I have my watch list which is in Boolean where I can then check if I the movie is in the watch list so let's do a watch list and then I want to use inary so if this is true let me return something and if this is false let me use some colon and return something else so if this is true what I can do right now just for demo purposes is return a little um let's say H1 tag and let's say yes and if this is not true let's add an H1 and let's say no so if the item is added we say H1 yes and if no then no and if I now go back and hover over these you see no if I hover over here no no and no why is it no because these items are not in my watch list great so now let's actually make it look good and actually style it so let me delete this first age one let's use a form element I will for now delete the action I will add it later then inside of here let me use the button component again imported from our components then inside of here I will now use a heart icon imported from Lucid react this is in self closing tag let me give it a class name of width four height four and text which will be red of 500 then of course I also want to give my button a bit of styling so we will give it an variant and the variant will be outline and I want to give it in size and this will be off size icon let's now also do the same for our um turn where this is not true so let me uh return a normal form element let me give it a button component and then inside of here let me again render a heart and for the class name we will do an width of four and height of four but I won't add any color uh I will just add the size for the button we have to do the same as here so we have to add an variant let's do that this will be again outline and for the size again this will be just the icon if I now save that and go back and hover over these you now see on the top right this little um icon with the heart and if this would be no true the heart would be red now I think the next step we should do is render the title the description and a bit of info about the age etc for that we will go under this diff so right above these empty tags and then let's create a new diff element let's do a class name padding of five absolute positioning bottom of zero and left also of zero inside of here I will now create an H1 tag and I want to to render our title if I know save that and go back and H over the uh movies you see the title at the bottom this looks nice let's also style it so let's give it a class name which will uh right here be font of Bolt let's do a text which will be large and let's also do a line clamp of one and why do I add this line clamp one right here well I want to be sure that the um title is maximum one line and not any longer because there could be an example where the title is longer and I only want to render one line if I save that and go back you now see the title is way bigger and has a nicer font so this looks very nice now the next thing I want to render is the age the release and the time of the movie so let's do a diff element let's do a class name of flex Gap X of two and I think items of Center to Center them and then inside of here let me render the pag and let's say 2023 I of course will later get them through the I I app props but for now let's just do it hardcoded 2023 that the next pag will be 12+ and the next P tag let's just say 150h if I now save that and go back and hover over it you now see the year the age and the time now let's actually get it through the I props so what do I need I need to get the Year this will be of type int or type number I'm sorry then I want to get the H will be which will also of type number and the last thing I need is the time so let's do time and this will be again a number if I now save that and go back I can now add this things so let's add the H this should be of movie. H and as you see I don't get that so I have to select that I want to get the H let's set that to true I want to get the release so let's set it to true and I want to get what else was it the duration that's set a to true if I now come back I can now now right here get the um how was it called H then I have to get the time and this will be movie. duration and the last thing I want to get is the year which will be movie. M release if I now save that and go back I can now actually use those items right here first of all let me get them right here through the params so the H I want to D structure that I want to get the time and I want to get the year and now I can use them right here in my front end so in inside of here I can render the year inside of here I can render the um H and then inside of this P tag I can render the time so if I save that and go back you still see we have this data right here and it's also different for each movie I can now also add the H at the end for the time so time H then for the h let's do a plus and for the year we'll live it like that so if I come back you see that looks very nice uh I I think I should add uh delete this space right here I don't need it let's go back so that looks quite nice the only thing I want to do now is also style the PEX so let's do that for the first PEX so where we render the year let's do a class name a font which will be normal and let's do a text which will be small for the second pag which is the H let's do a class name of font which will be normal border let's do a padding y of 0.5 padding X of one and a border which will be gray 200 round it and let's do um text which will be small if I save that and go back you now see that our H right here has a nice little border and I think that looks way better and then for our um time let's also style this P tag let's give it a class name of let's say font which will be normal and text which will be small so that looks very nice and now let's actually render our overview so under the pag and under the D tag let me get a new ptag let and inside of here let me render the overview if I now actually save that and go back and hover over our movie you see yeah that does not look good at all the overview is way too long so let's style that so let's give our pag a class name I want to give it a line clamp of one I want to give it in text of small I want to give it in text which will be gray of let's say 200 and let's also give it in front of light if I now save that and go back you now see that this description is only one line long and because of the line clamp uh we limit the size and at the end we have these three dots so that looks very nice in my opinion and now I actually think we can make this movie player work so right now if I click on this uh play button you see nothing happens so let's make this work to make this work I will again go inside of my app folder inside of the components folder and create a new component called um play video model. TSX now inside of here let's start as we always do with an export default function let's name it um play video model and let me open that function and then inside of here I can for now just return let's say a H1 with hello and for now I will actually return nothing inside of here for now let's actually create a interface because I want to get a few params first so let's do an interface I app props and then inside of here I want to get a title of type string I want to get a overview which will also be of typ string I want to get the YouTube url which will be of typ string let me also get the state which will be of type Boolean and let's also get the change state which is of type any so now I can get it through the params right here so let me D structure it this will be of type I props and now I can get it right here so change State I can get the overview I can get the state the title and the YouTube url now inside of this um play video model component what I want to render now is if I go back to our homepage right now you see this play video um icon what I want to do is when I click this icon I want to open a new model and then inside of this model the video will play and we will see a bit more information so let's do that and to make the model work we of course also have to actually install something from shaten UI if you now go to shaten UI we'll have to install the dialogue and with the dialogue you can test it out right here if I click on the button we right here open a model and that's exactly what we want so right here on the installation let me copy the CLI command let me open my terminal let me stop my def server clear everything and paste the command to install the dialogue this will take a second let's wait and now this has installed so inside of this return statement I can now get the dialogue imported from our components inside of here I have to give uh two properties actually so first of all I have to tell the dialogue when it's open and for that we have the state Boolean so let's set open true to our state then I also have this onopen change property and with that I can then manipulate my change state so let's do an inline Arrow function right here and then let's set change state to the uh different to the the opposite value of state so in basic terms what we do right here we tell our dialogue hey be open when state so when the Boolean is true and if the state changes so if we click on close for example then set our change state to the opposite value of state so if it's currently open so if the state is currently true the Boolean then make it to false and close the dialogue this is what it means basically now inside of this dialogue let me use a dialogue um content and this is imported from our components let me also give it in class name I want to give it on small devices a maximum width of 425 pixels and for that I will again use the custom value with the arrays now inside of dialog content we can use the dialog header so let me import dialog header from our components and then inside of here I can use a dialogue title again imported from our components now let me inside of we render our title then under the dialogue title let me also get the dialogue um description this is again imported from our components and let me render over overview so if I now save that and reload the page you see I get an error and that's because my def server is not running so let me restart that and let's reload the page so now if I test our button right here and click on it what do you see well you see nothing because nothing happens and that's because if I go back to my movie card component right here I haven't imported this play video model anywhere so let's actually import that and to do that what we'll have to do is go under the ptag and under the diff tag so right above this empty tags we will go and import our play um video modu this is in self closing tag and we get now a few errors and that's because we have to add our properties so right here let's start simple let's give it right here in YouTube url this will be equal to YouTube url then the next property which we have is the key and I will give it a value of movie ID then the next property which we have is the title let's give it right here a title then the next property which we have is the overview and this will just be equal to overview and the next two properties which we have is change State and State so let me actually first of all get these two properties right here and for them to work what we have to do is actually first of all create state so on top right here above the return statement let's create a normal use State uh hook so let's right here get our um getter which is open and our Setter which is set open and this will be equal to use State and the default uh state will be false and what I can do now for our state is uh add my open and for my change state is get my Setter which is set open so now you see we don't get any errors anymore actually and now if I go back and reload the page we get an eror and it tells me right here you're importing a component that needs use state it only works in a client component so to make it short right now inside of our movie card our movie card currently is a server component but since we want to use use state which has to hydrate on the client we have to mark this component as use client so on top let's actually do that and Mark it as use client if I now save that and go back actually without the page you see we don't get any errors anymore so now if I actually try and click on a circle right here let me do that um nothing happens why is that that's because right now in the movie card right here you see our button for our play circle does absolutely nothing but what I want to do is if I uh click on it I want to set open to true to do that that's very simple let's add an onclick Handler we'll have an inline function right here inline Arrow function and then let's set set open to true if I save that and go back and now actually click on that you see our model opens with the title and the description now one thing I could do is actually make this overview a bit smaller so again add a line clamp since this overview is a bit big so if I go to my play video model let's add for our dialog description a class name with a line clamp of let's say three if I save that and go back I think this looks way better so now I think the next step is to render the release date the age and the duration so let's again get that through our um I prop so let's get first of all a release this will be of type um number then the next thing I want is the AG this will be also of type number and I want to get a duration which will be also of type number let me also get it right here and the structure it so age let me also get duration and release so now if I go back to my movie card you see I again get an error since I have to add it so now I can give my property H also the value of H then let me also get right here the duration which will have in value of time and then the last one is release and this should be just year if I now save this I can now actually use these items in my play video model component so under my dialog description let's create a new diff element let's give it a class name which will be Flex Gap X which will be two and items which will be Center then inside of here I want to render a P tag and inside of here let's actually render um the release date so release now under the release date I want to uh render the recommended age so let's do a P tag and let's render the age and then the last P tag will just be the duration so let me render the duration if I now save that and go back you now see the uh release date the recommended Ag and the time let me also add an H for duration and a plus for H since that's a minimum Ag and let me also actually style the H so let's give it a class name and this will just be border padding y again of 0.5 padding X of one and border which will be gray of 200 let's also good and rounded and I think that uh that should be all if I now go back you see this looks very nice so now the next thing which I want to do is actually play the video or the trailer in that sense and that's again very simple let's go under the dialog header and let's render a i frame now now for the iframe we have to add in source and the source will just be the YouTube URL and we will have to add in height the height will be 250 if I know save that and go back what do you see well you see right here our trailer I can then click on that and watch the trailer also right now you see the width is not completely 100% so let's add a class name of w full if I now save that and go back you see that looks very nice I can now check right here this uh movie or let's check this movie right here this works perfectly at you as you see so now our model is fully working and I can hover on each movie as you see right here so now what's the next step since that works everything I think what we could do now is make these two buttons work right here so the see more and the learn more button so let's do that so to do that let's actually go back uh to this component and this component is called movie video so let me uh uh open that and now you see right here we render two buttons now if you can remember again if you go to the play uh video model we have to pass State and if you and I think you should already understand that in EXs 14 if you want to use State the component have to be marked as use client and right now our movie video component is in server component since we also fetch data so we have to break these two buttons into a component to a separate component and for that let's open our Explorer let's go inside of the app folder components folder and let's create a new component called movie buttons. TSX now let's first of all mark it as use client since I already know we will uh use state which has to hydrate on the client then let's first of all create a function so let's do in export default function let's name it movie buttons and let me just return that right here now for the return state statement let me return that let's use empty brackets since I don't want to show it up uh since I don't want to use a diff that shows up in the dawn then let's use the button component we have to import that from our components and then inside of here let's just say um play let me also actually use an um icon before the play so let's say um let's search for play circle so we'll import that from Lucid react as always and we also have to get a bit of styling so margin right of two let's give it an height which will be six and width of six so right now we could actually test out how it looks like so let's go back to the movie video component let's delete these two buttons and let's import our movie button component or movie buttons component if I now go back and reload the page we would see in a second right here this button play so now we have this icon and a text play which looks quite all right in my opinion but but still I think the play is actually a bit too small the font so let's again go back to the movie buttons component and let me style the button so let's get in class name of text large and a font which will be medium if I now save that and go back you now see the font is way bigger and that looks in my opinion even better now let's actually also render the second button so under this button let's get the second button and let's uh right here render a info icon again imported from Lucid react let's give it the same class name as right here so let's do a margin wi of two a height which will be six and a width of six and then uh after the icon let's say learn um more if I now save that and go back you now see we have two um buttons right here learn more is I don't think spelled correctly now it should be and that looks quite all right in my opinion so now right now these two buttons have the same background color this of course does not look good so let's actually change learn more to a different color so let's sty the button let's go a class name and let's say text of large let's do a font which will be medium let's say a BG of white and I don't want it to be white but I want it to have an opacity of 40% and that's why I use the slash right here then let's do in Hover which will be BG white of 30% so the opacity is now 30% and the text will just be normal white if I now save that and go back you see that does not look perfect this is transparent this shouldn't be uh here I have misspelled white so let's spell that correctly and if I now go back you see this looks way better and if I hover it that looks also great now if I click on the buttons you see nothing happens so let's change that so first of all we are going to have to create a new state so on top let's do const and let's do open and set open and this will be equal to use State the default state will again be false so at the start of the render so when the uh component renders I want the dialogue of course to be closed and only when the buttons are open I want to open the dialogue now for the button we can add a onclick Handler so let's do an onclick and let's do an inline Arrow function and let's do set open and let's set it to True let's also do it the same for this button let's add an on click with an inline Arrow function and let's say set open and make it to true but now this will still not work because if I go back back you see well nothing happens and that's because I have to add my play video model component so under the button let me now import play video model and now you see we get an error and that's because I have to add a few properties so I have to add an AG a duration overview Etc let's first of all add the state and this will be just equal to open then let's add the change State Property this will be equal to set open and now for the rest we actually have to create a inter interface so on top let me now create a interface and let's name it m i app um props and let me open that inside of here I want to now get an overview which is of type string I want to get a YouTube url which is also of type string I want to get an ID which is of type number I want to get an age which is of type number I want to get an title which is of type string and let's also get in release um date which is of type um number and let's get a duration which is also of type number now let me destructure it right here in the params so let's destructure it and give it in type of I app props and now we can get these values so the age the duration the ID the overview the release date the title and the YouTube url so now right here let me actually add all of these properties so for the h this will be of value H for our duration this will be of value duration then for our key key this will be of uh value ID then I want to get the overview and the overview will be of type um overview then I want to get uh the release and this will have the value of release date and then what else do we need the title this have will also have the value of title and at last YouTube url which will have the value of YouTube url I can now save that and if I now go to the movie video component and scroll down you now see the movie buttons have an error and that's because I now have to add all of these uh properties so for the h what we can get is the data. H and now you see we get an error it tells me type number or undefined is not assignable to type number so let's do an s number then the next field we want we want to get is duration this will be of type data do duration let's again do at as number so now the next property is the ID and this will be of type data do ID D and again let's do an s number then the next field which we will have is the overview this will be of data. overview and we again have to ask string then the next property is the release date this is data. relase as number then the next field which we'll have is the title which is data. title as string and then we should also get the YouTube URL and this should be of data. YouTube URL and you see I don't have it so let me select the YouTube String right here and set it to true and then right here I can now get our YouTube URL and Mark it as string now the last property which we have is the key prop and this is to prevent hydration errors or Warnings so let's do data. ID so now this should actually work so let's go back let me click on play and we see the movie right here let me click on learn more and the same happens so this now also works so our movie play right here works we have the title the description we can click on this um button and then we see the description and the movie right here and I can also do the same with recently addit I can click on it and this also fully works so now I think we should actually make the categories work so right here we have the three categories so TV shows movies and recently added and what I want to do now is if I click on each category I want to see the movies which are based on this category and At Last I also want to create my list and then also render it right here on the bottom so so now let's actually start with this categories field now again this is actually very simple we'll open our Explorer let me first of all close everything and then let's go in the app folder and then inside of the home folder I want to create another folder and I will now wrap it inside of brackets array brackets and give it a name of genre so what do I do right here well beforehand we have created the home folder just with a folder and a name now we have created another folder but we have wrapped the name ins inside of array brackets and with this I tell next sharers hey I want this um folder or this URL at the end I wanted to make Dynamic so I can pass anything get it then through the params and then fetch it based on the name so that's what we'll do this is now a dynamic route so let me now uh save that and inside of here let's do a page. TSX so now again we start as we always do let's do export um default function let's name it um how do we want to name it category page and then let me open that function so what we can do right now is first of all test out if this page works so let me right here return H1 so let's in return H1 hello from the category if I know save that and go back let's click right here on TV shows and we should get redirected and we see hello from the category let's click on movies yes the same works and recently added this also works works and now the cool thing is that recently added has an underline if I click on movies you see now the URL has changed to SL movies and the movies has now an underline so I guess now the dynamic nafar that's how I will call it works now perfectly so now let's create our category page and now the first thing I think we should do is actually fetch our data so above our export default function let's do a async function let's do a get data and then let's me open that function now again our category page has in total Three Links so TV shows movies and recently added and I of course want to fetch the movies based on this uh category and we only have one page so how do we do that well we can get the search params and then create a switch statement and then query based on the case so how do we do that so through our params right here we can get the category this will be of type string and now right here inside of our Asing function we can do a switch statement so let's do switch and we want to B uh create a switch statement based on our C category right here and then let me open that now we will have multiple cases so now what's the first case so right here we have TV shows how does the URL end well/ shows so what we can do right here is create a case and this will be based on the show's name then let me open open that and now we can fetch everything which is um required for our shows category so let's do a constant data which will be equal to await Prisma Prisma is imported from our utils um movie. find many and then I want to find many where our category has the name Show Now show this is a singular word you can also right now go to our seat page so in our seat uh folder the page TSX so you see right here for this uh right here record our category is a show if I scroll up for this record it's movie and if I scroll up a bit more for this record we have a category of recent so that's what we do right here we want to find the um items where the category matches show so that's what we do right here that looks fine and now we can select everything we need so let's do a select statement and I want to get the H so let's set it to True let's get the dur let's set that to True let's get the ID let's set that to True let's get the title also to True let's get the release let's get also the image string and let's get the overview then let's get the YouTube String then right here we have our watch lists and now right here I want to find them where the user ID is equal to my user ID and again we also have to get that through our params so on top let's do a user ID which will be again of type string so right here let me pass the user ID and that's actually all we need so what I can do now is actually return our data now there's one important thing if you do a a switch statement you also have to have in default case so right here we can now add a default case and if it's default so if no of the uh switch cases are true we can just do a throw new error so that looks fine now let's get the data through our font ad so let's do a constant data equals to aate get data and now we get two errors first of all the tell SCE right here arrayed expressions are only allowed within async functions at the top level of modules so let's mark our function as async and now the second ER it tells me right here expected two arguments but got zero and the two arguments are the category name and the user ID so let's get them so first of all on top I can do a const session this will be equal to await get um server session and get server session is imported from next off and then let's pass our off options imported from our utils folder now we have the first step we got the session and from there I can get the ID the second step is now to get our category name and we will do that with our params so right here we can destructure our params and now types script complaints and it tells me params is declared but it's never red that's fine and Bing element params implicitly has an any type so let's give it and type and params will have the type of um genre and genre will be of type string so now what we have done this we have the structured params right here through our parameters and then we tell params that it has a type of genre which is string so now we can pass these items to our a get data function so first of all let's let's pass our params do genre and then for the second param we will have the session. user. ID and you as you see we don't get any ID so now that's of course a problem so for now I will just give it in default value of just that say strings um a b c and then at the end of the tutorial I will think about how to fix the error but for now I will leave it as like that and later on of course I will change it to the actual uh user ID or user email I will think about how to do that but now we actually fetch our data so what I can do now is very basic let me delete this old return statement and let's do a new return and let's just say um div and then let's get our data let's map over it then we will get a movie and then let me just um return that then inside of here I can now just create a H1 and then render a movie. title let's also give it in key so that we don't get any errors and the key will be movie.id if I now save that and go back I can now click on TV shows and as you see I get 1 2 3 4 five TV shows so that looks good if I now click on movie I will get an error and that's because I haven't created any cases for the um movie category so let's actually do that for the movie category and for the Recently Added category so let's first of all start with the movie case so let's right here create a new case this will be called movies and then let me open that inside of here let's again doing cons data equals to await Prisma movie. find manyu inside of here I want to again get a where statement and I want to find all movies which have the category that is equal to mov V in a singular word then let's again select a few things so let's create a new select statement then I want to get the age I I want to get the duration I want to get the ID I want to get the release date I want to get the image string I want to get the overview I want to get the YouTube string and I want to get the watch lists and where should be equal to our params again so our user ID should be equal to how is it called at on the top right here um also user ID so let's do user ID that looks fine again that's great uh the last thing I have to do is of course return that data so let's you return data so if I now save that and go back and click on movies I don't see anything why is that let's see uh I get an error right here Ah that's because I haven't selected the title so let's select the title and set that to true if I now go back we should now see the title yeah for movies we have two uh movies as you see right here let's now also do the same for recently edit so let's create a a new case and this will have the name recently and then let's open that inside of here we'll actually do again the same so let's do con data equals to await um Prisma movie. find many now again I don't want to get all movies I want to get only certain types where the category is equal to resent again in a singular word then let's again select a few things and actually let's just copyed from here so I will copy this whole select statement um from movies since it's actually the same and let's just not waste any time right here paste that and that looks fine so now let's try it and click on recently added and now we get an error where is that that's because I don't return any data so let me right here now return the data and if I go back reload the page you now see that all links work so our homepage Works our category Pages work and now we have to actually also style our category pages so let's do that right now um to get started let me delete everything inside of the return right here and let's create a new return statement and how do we want the movies to look well again we want to create a grit so if we are on a bigger device we want a column of four so four movies on the horizontal side if we're on a smaller device then three calls if we on a even smaller device than only two columns and if we are on a mobile device so on your phone we only want to have one column so that's exactly what we'll do right now so let's write your git and class name of grit then if we on a mobile device let's do grid calls of one if we're on a small device let's give grid calls of two if we on a medium device let's give it grid calls or free and if we on a large device that means right now on a computer let's give it grid calls of four let's now also give it some padding if we on a mobile device let's give it padding X of 5 if on on a small device or bigger let's do padding X of zero and let's do margin top of 10 and a gap of six inside of here I want to now uh map over my data so let's do right here data do map let's get the movie and let me return that so first of all let's create a diff right here let's give it an key to prevent any errors let's do movie. ID let's also give it in class name and let's say relative and height of 60 now inside of here I want to render an image so let's use the image component by next JS this is imported right here on top from next SL image now right here we have to give it two props first of all a source and then also an ALT tag for the alt tag I would say movie and for the source tag this should be movie. image string let's also give it in width and height to prevent any errors so in width of let's say 500 and a height of 400 then let's also give it in class name and for the class name let's just do a rounded which will be small Let's do an absolute uh positioning with of full h of full and let's save it right now if I now go back you now see right here 1 2 3 4 five TV shows so that looks nice now there's one thing right now I don't like you see that the aspect ratio is not correct and to actually fix it it's very simple let's just do right here an object and we want an object of cover if I now save it and go back you now see that looks way better and the aspect ratio is now correct so now since we see the movies let's now create the hover effect uh which we have right here on the homepage so that I can hover on each movie and see more info to do that let's go back and then under the image let's create a new diff element let's give it a class name of height 60 and I won't explain these class names now since they actually the same as right here in our homepage you can now either go to our homepage and copy it from there or just follow me and um write them like that but again I explained them already beforehand so so you should Now understand why I create these class names so let's give it in relative positioning um let's give it in Z of 10 let's do a width which will be full let's give it a transform let's also give it a transition property with an duration of 500 milliseconds let's do a hover which will be scale of 125 to scale it to 125% if we are not hovering Let's do an opacity of zero and if we hover let's do opacity of 100% to see our hover object now again we of course have to create the gradient so from the top where it's um transparent and to the bottom where we have in darker color so let's right here create a diff element let's give it in class name which which will be BG gradient to bottom since we want a gradient from the top to the bottom then let's do from transparent um via black and let's do 50% since I want to have an opacity of black which is 50% and let's do two completely black so if I don't add any slash the opacity is automatically 100% now let's also give it an Z index of 10 width of full and H of full inside of I can now uh finally render the image so the hover image so let's again use the image component and then inside of here we have to pass our source and for the source we will use the movie. image string let's give it again an ALT tag which will just be movie let's give it also a width property of um 800 and a height property of also 800 now again why do you have to add this width and height properties well that's because if I don't do that I will get errors with the next image component because it has to know to which size to uh because the image component has to know to what size it should optimize the images to now let's also give it in class name of uh absolute positioning width which will be uh full height which will be also full then we want to give it in minus that index so that it shows underneath this overlay right here so let do a minus set of 10 and a rounded of LG to have a bit of a bigger rounding if we now go back and test it out you see if I hover over the images I see them that looks nice now one thing you should also see is if I hover over these images the uh the aspect ratio is again incorrect so let's again fix it and do a object of cover and if I do that let's again go back y this looks way way better so now the overlay works the hovering works let me also write here for the stiff which wraps the image also give it a border and a a rounded of large let's go back uh do we need the Border actually yeah no let's maybe delete it I don't think it that looks nice let's go back yeah let's leave it like that that looks very good so now what I want to render is uh the title again description and everything else and for that we can now use our component which we have also used in the homepage so the movie card component so now under the image component right here let's import the movie card component from our components if I now click on control space bar you see the props which we have to add right now so let's first of all start with the key for the key we can give it a movie. ID then the next property which we have is the H for the h we can do a movie. h then what's the next property the movie ID this will just just be the movie. ID then we will have an overview this will be the mo uh movie. overview then the next property this will be the time and this should be the movie dot how was it called right here duration then the next property the title that's your a movie. tile what else do we have watch list ID for that we'll have to do a movie.at lists we want to get the first item in the array so right here we use an array brackets with zero with that I get the first item in the array and then I can do a do ID and let's save it like that now the next property which we have is the watch list and this will again be the Boolean where we know if this item is in the watch list or no uh or not so let's do a movie.at lists. length and if this is zero and if this is bigger than zero we know that this movie is in the watch list so let's do Turner let's say true and if this is not uh bigger than than zero so if the length is undefined or null in that sense this will be false and then the next item which we have is the year and this will be the movie. um release and then the next item which we have is the YouTube url which will be movie do um YouTube String now this should be already all Let's test out if it works and right here we get an error cannot read properties of undefined reading ID yes of course because this item is not um definitely defined it can be not defined so let's add in question mark right here so it could be defined or not defined so now let's see how it looks like yeah that looks nice the only thing is that right now our play circle is on the top that's not quite correct let me check what the error is so H 60 relative transform transition that's all right so the error must be somewhere inside of this stff um BG gradient da da da z uh 10 with full AG full rounded LG so I already see what the error is of course our play button right here can't be in the center if we don't position it to the center so what you have to do right here is add a flex element and then items which will be Center and just toy which will be also Center if I now save it and go back you now see that the play button is in the center and this looks now very nice so now I think let's check out if everything works so let me click on that yes you see right here the model with the trailer and uh all the information which you need for that if I click on home I see the home screen with the video I can click on play I see right here also the trailer and this also works everything let me click on movies yes this also works let me click on recently added and you see this also works let me also maybe check how the homepage looks on mobile so let's make it smaller yeah this looks fine let me click on the movie Yes the model also open opens so you see this also works so what do we do now we see this works everything so maybe we would uh should now create a watch list since if I now click on my list right here you will see we will get actually an error a 4 or4 Page could not be found and this is because we haven't created the route or the folder structure for this route right now so if you right now go to the navbar dtsx component right here you will see that the URL for my list or my wish list uh watch list I'm sorry is /home SL userlist so what do we have to do so for you if you think about it we have an home folder or we have an app folder in this app folder we have all the routes and now we have in Home Route how do we now generate a user route with an child route which is list so we create a normal folder called user and then inside of the user folder we have to um put a child folder which is list and then of course we have to create a page. ESX to create a route so now inside of here we can uh do the same as we always have to do let's do a export default function let's name it um watch list and then let me open that function inside of here I can now return a H1 and let's say hello from the um watch list if I now save that and go back and click on my list and that's what you see right here we we now see an H1 with the text hello from the watch list so this works now before I create the UI I think what we should do right now is actually do a fetch call or fetch our data so let's do that right now so on top above our export default function let's do a async function get data and let me open that function inside of here I want to now fetch my data from the database with Prisma so let's do a constant data equals to await and Prisma which is imported from the u. watchlist and I want to find many now I don't want to find every watch list from every user I only want to find the watch list and in that sense only the results which belong to the current user or or to the user which matches the watch list user ID so again to make it a bit more simple we have multiple watch lists with multiple different um user IDs and I only want to find a watch list which is equivalent to the uh to the current user which is logged in and stored as in session so how do we do that right here we have anware statement and where and we want to find only the watch list where the user ID matches our current user ID now how do we get our user ID we get it through the params so that's your user ID and this will be of type string so I can now save it and tell right here user ID so now we are sure or now we tell Prisma hey we only want to get a watch lists where the user ID of the watch list matches our uh user ID and now I want to select a few things since I don't really want to get the data from the watch list but what I want to actually get is the data from the movie model right here which has a relation so let's right here get the movie and then let's select from the movie a few things I want to get the title I want to get the age I want to get um the duration I want to get the image string I want to get the overview I want to get the release let me also get the ID let's get the watch list um array and then let's also get the um YouTube String to actually show the um trailer so now we have an fetch call right here we fetch our data but now we also have to return our data so let's right here do a return data and now we can get it in our front end so let's do a con data which will be equal to uh aate get data now we you see we get two errors so first of all we have to mark our function as async since we want to fetch data so let's mark it as an export default async function and then the second error right here is if I hover over get data it tells me expected one argument but got zero and the argument which it's uh which it expects is the user ID and to get our user ID let's use our session so let's use an const session this will be then equal to aate get server session which is imported from next off and now I have to pass my off options so now I get the session from the user and now as I already told you I currently don't uh don't get the ID from the session so I can't really pass the ID right now and I haven't really thought right now about how to fix it so what we will do right now just as in temporary fix is add an default value of ABC and then I will fix it later on so now what I think we can do is actually create the UI even though the data which will be returned will be null or undefined or the array in general will not have any items and that's because we just don't have any items in our watch list but still let's actually already create the UI so when I add the functionality so that we directly see if the items are in the array uh in the watch list or if they're not now to actually not waste any time I will copy the code right here from our genre page since actually the code will be exactly the same and I don't want to waste any time so I will copy this uh whole code right here from the return statement and then let me delete this old return statement and paste the new return now you see we get a few errors so let me import the image component now you see it does not import for me automatically sadly so on top let me do a import image from um next slash image now this error should be gone yes that looks fine let me also import movie card right now from our components and now I get a few more errors so right here this shouldn't be movie.id now anymore but a movie. movie.id now the same also for the image string this will be a movie. movie. image string and then let's do as string now that's also the same for this image so let's say movie. movie. image string as string now for the movie card that's also the same we'll have a movie. movie. ID then for the h this will right here be a movie. movie. as number then for the movie ID let's your movie. movie.id as number then for the overview this will be movie. movie. overview as string let's do the same for duration movie.mov do duration as number then for the title this will be a movie movie. tile as string now for the watch list ID this should also be a movie. movie now right here let me add in question mark since it could be unfined and then as string then for the watch list ID this should also be a movie. movie let me add a question mark right here if I now hover over it right here it tells me movie.mov watch list. length is possibly undefined so let me do right here as number then for the release this should be movie. movie. relase and for the YouTube string movie. yoube string this is an as string and for the year as number now we shouldn't get any errors anymore and yes we don't get anymore what I could also right now do is actually wrap this whole watch list so let me copy it and I'll wrap it inside of this empty brackets and then right here under this empty brackets let me actually create an H1 tag so let's do an H1 tag and let's say um your watch list if I now save that and go back you now see your watch list let's make it actually a bit bigger so let's do a class name and let's do an text which will be white then text which will be 4 XL font which will be bold underline let's also do a margin top of 10 U padding X which will be five and on smaller devices or from small to bigger devices padding X will be zero let's see how that looks yeah that looks very nice and as you see we don't get any items and that's because no items are currently defined in our watch list so now that you see all links work so the homepage works that uh these category Pages work and the my list page works I think we should now create the functionality where I can add a movie to my watch list so let's do that now to do this that's actually quite simple so let's think about it there are actually just two options that we can have right we can either add our movie to a watch list or we can delete the movie from the watch list so now if you think about it that means in basic terms we will need two server actions one server action to pass a movie to the watch list and one server action to delete a movie from the watch list so now you could of course just create these server actions in the component itself and that's cool you can do that but I will actually create a separate file where I can store these two actions so in the app folder I will create a new file called action. TS and then inside of here I will create two um server actions so let's first of all create the first server action which will be to add the movie to the watch list so let's create a export async function this will just be um add to watch list and then let me open that function right now now this is currently just a normal async function which runs on a client and now to tell next sh also react in that sense that this is a server action we have to uh mark it as use server with that I now tell react hey this is in server action please this should only one on the server never on the client so with that this is also now safe to use any seets you want inside of here now what do I want to get also through the params I want to get the form data so let's right here get form data and form data has a type of form data so now we have created our first server action and now let's actually run the query so let's do in con data which will be equal to arrate Prisma Prisma is imported from the utils folder do watchlist. create and now inside of here I want to create data and now we have two options which we have to pass so first of all we have to pass a user ID right now let me just mark it as in string and we we have to pass a movie ID now the movie ID has a type of number so if I would now try to give it in string you would see we'll get an error since it tells me type string is not assignable to type number so now for the user ID for now I will again just give it the default value of ABC again I will fix that later but for now that is fine and for the movie ID I will actually have to get it through the form data so what we can do now above our const data is do a const movie ID and this will be equal to form data. getet and I want to get the movie ID and then now for our movie ID I can delete the strings and if I would now Pass movie ID you will see we'll get an error now why is that that's again because our movie ID expects a number but our movie ID type right here which we get through the form data is not a type number so we can convert it to a type number uh quite easily with number and then passing our movie ID right here so now you see we don't get any errors anymore and that looks very nice so now I can actually save that and before I create the second server action let's actually hook up the functionality to make this server action work so now to make it work it's quite simple I'm now on the movie card component and there we have two forms so the first form right here or the first button is to delete a item from the watch list and the second it uh button or form is there to add a item to the watch list and now we have only currently one server action so we will use right now the second form right here now if we go back to our action it expects a movie ID and I have to pass it right now how do I do that in the context of next shares 14 or even ex 13 so I will have to add an input and now that's very important this will be an input type of hidden now I will have to give it a name and if I go back to my action. you see I get the form data with the name movie ID so if I copy it let me add it as a name and then for the value this is important the value will be our movie ID and you see we get it right here through our perams so now I can write here give an a value of movie ID so now you see we have added the input now still this won't work because our form is actually not hooked up to anything so we'll now add a action and the action will be called if we go back right here add to watch list so let me do add to watch list and now you see we don't get any errors and that looks fine so now let's test out if it works so let me go back to my code let me reload the page and you see we get an error I was already expecting the error so let's read it so let's read through it it does not allow to Define inline use server annotated server actions in client components to use server actions in client components you can either export them from a separate file with use server at the top or pass them through the props from a server component so as you see this error actually already tells us the solution right here from a separate file with the use server at the top so what we have to do right now in action. TS is Mark this file at top at the top with use server if I now save it and go back and reload the page we the error will go away and we can now test out if our watch list creation works so let me click on this right here and does something happen no not really let me click on my list let's see if we get an item and yes we do get an item now why did our item not refresh on the homepage actually now that's because we haven't told next shares to hey refresh that page because when we clicked on my list it did a new uh fresh request to our database but our homepage had stale data which did not get revalidated so now I have to somehow tell next shares hey when I click this form please revalidate the data so I see um that I have added an item to the watch list so it's quite simple actually to do that with next shares since all you have to do is revalidate the cache and for that there's a very nice helper function so inside of our action I can now use the helper uh function called revalidate path this is imported from next cache and now I have to tell actually this function which path I want to revalidate now the interesting thing is that this movie card is not actually um does not belong to one certain path but it can be have multiple paths so what I will do in my movie card is add another input so let's do another input which will be type hidden and with this input I will now tell my action on which URL we are currently on so let's give it a name right now and the name will just be path name and now we also have to get our path name somehow and for that there's a nice helper function so above our return statement that's your const path name which will be equal to use path name path name is imported from next navigation and now I can actually get the path name so now right here let me give it now a value and the value will be path name if I now go uh copy this name right here so for input which is path name and go back to my action I can now right here create a new constant this will have the name path name will be equal to form data do get and I want to get the path name so now right here I get the path name and I can now pass it right here to my revalidate path name um function so now you see also we get an error so if I hover over path name it tells me argument type form data entry value or null is not assignable to parameter of type string so let me Mark it right here as string and now we don't get any errors anymore so in basic terms what do we do right here so we created in server action we we got a few values from our form data then we just uh post our data to our database using Prisma and at the end we revalidate our path so that the cache gets revalidated and we see the result so now let's see how it looks like let me go back let me reload the page now you see if I hover again on this movie our icon has changed to the red icon since the movie now exists in the database or in our watch list now if I click on another movie so right here let me click on this movie click on the icon you will see it has now revalidated and I see directly that I have actually added the item to my watch list if I now go to my list you will actually also see right here the second movie both are now in my watch list so what do I want to do now now I also want to create a server action to delete the item from my watch list so let's go back to my action. ts and now inside of here I will create another function so let's do export async function this will be called delete from watch list and then let me open it function inside of here let me again get the form data so the form data will be of type form data and currently this is just a normal async function which runs on the client so let me again mark it as use server to tell react that this should be a server action and now inside of here we can again run our PMA query so let's do a con data which will be equal to array Prisma do watchlist. delete now right here we will actually have to tell um I guess Prisma what uh item we want to delete so right here we have the wear statement and now I have to give it an ID so the ID of the watch list so for that we will again go to my movie card and we will again use our um handy input type hidden and with the input type hidden I will give it the value of the current watch list ID so right now uh let me uh write here in the form create a input this will be of type hidden let me give it a name this will be watch list ID and for the value this will be watch list ID actually so we get it right here watch list ID and now I can use it right here now you see we don't get any error anymore and that looks nice also I will need this path name so let me copy this input right here and also paste it right here so now I have created two input type hidden so first of all where I pass the watch list ID and I pass also this in the second input the current path name so now I can actually get it right here in the action um through the form data so now let me actually create a new constant this will be called um watch list ID this will be equal to form data. get and now let me check how I spelled it right here watch list ID so let me copy it and paste that let's also as string and then the second value which I need is the path name so let's do const path name and this will be equal to form dat. getet and I want to get a path name so let me copy it and paste that also Let's do an as string to not get any errors now right here for the ID I can now give it the watch list ID and I also want to revalidate my path so let's use the revalidate path function and let's pass our path name which we want to revalidate so now in theory this should work so let's see if it actually works so right here let me um reload first of all the page to be sure that everything is compiled and now let me just delete this item and you see it did not work now why is that that's because if I go to my form uh to my movie card you see our form does not have any action so let me right now add an action and this should be called something like delete from watch list so now this should work so let me again reload the page and now let me test it again so let me click on it and the item is deleted let me click on that and the item is also deleted I can againest tested let me add this and let me add this and if I go to my list you see it right here so this now finally works as you see that's very nice so now instead of just um actually quering or creating the watch list within just default value of ABC I think I came to the conclusion instead of using ABC we could just store them using our email now in a perfect environment I would probably do it with an ID but right here next off we don't get the ID very easily so I will now actually just use the email and start with that I think that's actually safe enough because at the end of the day um our email or in this um project and next off automatic account linking does not work so attacks shouldn't be really possible so I think it should be safe enough to store our um watch list in association with our email so now if I click on the search icon I can now search everywhere where I use this ABC and then we have it right here in our home uh user list as you see and in our user list I just add the ABC let's instead of doing the ABC let's do a session. user. email this will now be a string I now get an error so let's ask string to prevent that then let's see where else I add an ABC I added right here inside of our um category page so instead of ABC let me again get the uh session. user. email as string and where else do I add it I think I add it right here in the action. TS so let me get the session first of all so that I can get the email so in con session um equals to await get server session and then let me pass our off options which I import from the utils folder so now instead of ABC I can just do a session. user. email as string and this should still work actually so now if I reload the page there's a weird thing right so right here tells me that I've what um added these two movies to my watch list now this is not correct these two what uh movies are associated with the user ID ABC if I click on my list you will see this does not pop up here because I only fetch the data which is associated to my um email now why does it happen right here well that's because I fetch the watch lists which are not associated to me I just uh fetch all watch lists right now so let's change that right now to do that that's actually quite simple so what we have to do is if I go actually to the um recently addit component we have right here where is it watch lists now currently I select the whole watch list but I don't want the whole watch list I only want to get the watch list which is actually associated with me and only me with nobody else so instead of true let me open that and then let's add a where statement and this should right here have an um user ID and now I have to also pass an user ID so let me get it through the params so let's do user ID and this should be equal to a string and now right here you see I get an error it tells me right here expected one argument but got zero so right here now let me get the session so let's do a con session uh equals to await get server session imported from next off and let's add the off options which are imported from the utils now I here I can now pass my session. user. email as string this is now all passed and now I can add right here my user ID so if I now save that and go back reload the page let's see and if I now hover over these movies you see they are not anymore associated with me so that's why I now don't see this heart anymore if I now click on it you will see this still works and if I click on my list I still see the movie I can unfavorite it again and then if I go back you now see it's again not favored let me click on that let's see if that works let's click on my list yet that yeah that works let me unfavorite it again and this also works and now I think actually everything works so let's test out if everything actually works let me click on play so it loads the model opens I see the title description the data and the trailer let me click right here on this movie this also works as you see and if I click on here this also works now let me try favoring it yes this works this also works you also see it does automatically revalidation and if I now click on my list so on my watch list I see the items right here so this also looks good now let me click on TV shows I also see the items right here as you see let me click on movies this also works and if I click on recently added this also works perfectly so now this looks good let me also see if I can uh successfully lock out so let me click on sign out what do we see it loads it loads it loads and I got locked out let me zoom in a bit let me now log in again um with GitHub right here and now you see I'm back and I'm logged in now there's one thing actually you now see these items are not associated with my list right here my watch list why is that that's because I've now logged in with a different account that means I have now a separate watch list and if I add these items to my watch list go to my watch list you now see them here so we have now successfully mastered this concept where we can have multiple users with multiple or with different watch lists and where I only fetch the watch list which is associated with the current logged in user so you see that works perfectly and I think we are now done and we have come so far that we can now actually deploy our application to the cell so now let's first of all and push our code to GitHub so now I'm on github.com as you see on github.com SL new to be exact so now let's create a new repository let's give it a name of Netflix next MJS YouTube then let's make it public and let me click on create repository so now you see GitHub gives us instructions on how to create a repository so let me open my terminal let me stop my death server let's clear a thing and let me zoom in actually so how do I get started let's do a get in it then let me do a get add everything so get add and then a DOT with that I add everything then I have to commit my code so let's do a get commit DM and for the message we will just say finished project then let me click enter now you see everything has been committed now if I go back to the instructions the next step is to create a branch so let me copy that uh and and paste it right here then the next step is to add in remote origin so let me copy it and paste that and then the last step is to push my code so I will just copy that and then paste that so now if I go back and reload this page what you will now see is that we now see the actual code which is nice so now let's go to Vel and deploy this application so I'm now on cell.com slne to deploy a new application let me click on right here Netflix next shares and let's import that and as you see the framework preset is automatically pre-filled that's good and now before I click deploy let me add environment variables so if I close my terminal let me open my EnV file let me zoom out a bit we now have all of these um secrets so what I will do right now is actually copy all of these secrets and then paste them right here inside of here now if I click on deploy this still won't work there will be an error with our authentication so of next off if you now go to the next off docs and go to the deployment Tab and search for verell right here tells me make sure to expose verell system environment variables that's fine it does that automatically and then the second step is very important it tells me right here create a next off secret environment variable for all environments you can use opsl la la la or use this URL to generate a random URL so it tells me I have to add a next off secret so let's do that I will copy this name right here next off secret then go back let me add a name and now I have to generate a secret or a value so I will just go to this URL I don't want to use the open SSL command and then let me copy this value now I can paste it right here add it and now we can click on deploy and it should work so let's deploy and see what the result is so now you see a production build which has been deployed nope we have an error now I already knew that we would get an error because that's very normal with vestel so right here tells me Prisma has detected that this project was built on Vel which cast which cashes dependencies this leads to an outdated Prisma client because prisma's autogeneration isn't triggered to fix this you can run Prisma generate we won't do that or you can learn more right here so I will uh copy this uh URL paste that and now we will come to the Prisma website and right here they tell you again what the problem is so the problem is since uses ver cell it will just generate uh it will just cash our dependencies and because of that the automatical Prisma generate command won't work so right here we have an solution and that's to add a custom post installed script and that's exactly what we'll do so let me copy this uh post installed script let's go to our package Json and then under our lint right here let me just paste that now we have to push our code again so let's get add everything within dot then let's do do a get commit DM and let's say added um I guess script let's click enter and let's do a get push this will now push our code to GitHub and verell will automatically rebuild our application so let's head over to our cell so I'm now onell and again as you see the automatic rebuilding has worked it now does it now rebuilds the application and now let's hope for the best and not to get any errors so now you see ver cell has successfully deployed our application so let's click right here and actually see how it looks like and we get an error or not an error Chrome wants to tell us that this site could actually be a dangerous site and why is that that's why uh that's because we have a Netflix name in our URL so that's fine since we don't want to have any competition with Netflix and this is no um dangerous site this is just in project so I will leave it like that we can click on details and then click right here on um where is it visit this unsave site so now that looks fine what do we want to do we want to log in and now we would think everything works right no it won't I'm sorry to break it to you if you click on GitHub you will get an error what do you see this site can be reached and it actually redirects to local 3000 why is that that's because when we created our um o off app in GitHub we had to give it an authorization call back URL and we gave it a local host 3,000 um authorization callback URL but now we aren't on anymore on low close 3000 but we are on an actual deployed website so what do we have to do well we have to head over to GitHub and now create a new oof app and also create in that sense a new client ID and a new client secret so let's go to GitHub so I'm now on the GitHub uh developer settings let me now click on new oof app let's name it Netflix production um I will have to give it an homepage URL let me just copy it from here um and also without this login so just the URL let me paste that inside of here and for the authorization callback URL it's the same I will paste the URL and then this will be in/ API SL off/ call SL GitHub and now that looks good I can now click on register application and right here we now get a new client ID and client secret so what I have to do now is go back to to cell actually uh go to settings click on environment variables and then right here we have our GitHub ID let me change that so I can click on edit right here and I have to add a new secret so I will go back to GitHub and copy my client ID so I can now go back and just paste it inside of here let me now click save let's also do the same for GitHub secret so let me click on edit let me go back generate a new client secret and now I can right here click uh copy my uh secret so I will copy that and then just paste it inside of here now let me click on Save and now this will not work actually since if I go back to GitHub and reload the page and click on GitHub it still does not work and that's because we have to redeploy application so that Rell can actually get the environment variables so let me click right here on project and uh not on project but on deployments then on this three dots right here and then we deploy we won't use the existing build cache so let's just click on redeploy and this will now redeploy our application and also in that sense our secrets so now you see our application has been again successfully redeployed so let me again open the URL right here um let me again click on details um visit this on Save site and now we can try to log in with GitHub so let me uh click on the GitHub icon and this should work yes let me click on authorize so I want to authorize myself this should now load and let's see let's see let's see D we got redirected to slome so this works perfectly so now as you see if I hover over a movie let me first of all zoom out a bit if I hover over this movie you see it's already in my watch list so I can now click on my list and now you will see in a second that I have now two items in my list which is correct you also saw that in the death environment I can now actually also um add another movie so I can click right here I'll get redirected now let me add for example this movie you will now see it will revalidate the data and now you see the red heart icon now there's one thing you should know this production deployment will be slower than our development uh version why is that that's because right here we use serverless functions which run on AWS and use the nodejs one time now the expense of that is that you have to wait for call start times now you could of course use uh Edge functions but then you couldn't use PMA since Prisma does not work on the edge so I guess that's a little bit the problem of Prisma uh or I guess also serverless functions you have C start problems and this takes a bit if the application is currently cold but what the cool thing is right now if I reload this page you would see it's very fast why is that that's because this whole data is cached so what I mean with that is that this project is static that means I haven't added any revalidate Texs and every and the data that we found from our database is fully cached uh from next shares this is very nice since it makes the page very fast and if you don't plan to add any movies to the database you can leave it like this if you now of course want to add movies to your database you of course should actually revalidate your cash I don't know every 30 seconds every minute uh whatever you want since I don't plan to add any movies I will leave it like that you can also see that if I for example now click on TV shows it's quite fast and that's again because it's static so now there's still one thing you probably saw it if I now click on lock out right here or sign out in that sense it will redirect us to log in and if I now click on log in this of course won't work and that's because I actually haven't added a new um I guess authorization callback URL I won't do that anymore since I want to go to sleep but you can do it on your own it's the same as with GitHub all you have to do is add another auor offer ation callback URL with our production URL and then also Google will work so now I hope you enjoyed this video so now enjoy your day and bye
Info
Channel: Jan Marshal
Views: 19,059
Rating: undefined out of 5
Keywords: nextjs 14, netflix clone nextjs, netflix clone react, typescript tutorial, learn typescript, learn react, learn nextjs 2024, web development tutorial 2024, 2024 coding tutorial
Id: mTW3V2IpOrg
Channel Id: undefined
Length: 231min 21sec (13881 seconds)
Published: Tue Nov 14 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.