Build a Full Stack App Fast: Mastering Next.js 14 & Supabase

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
today you going to build a full stack NEX js14 AB router application we are going to use superbase as our database as well as a way to add authentication to our app we're going to use Tailwind CSS for styling and then we are going to deploy our application using versel and the project that we are going to build is going to be a watch list I'm into watches as you may know if you watched previous videos but we're going to allow the user to sign in and basically create a watch wish list to where they they can add remove update edit do all those things to their watch wish list for watches they want to purchase in the future so without further Ado enjoy this course I think that you going to learn a ton try to make it all the way through try to really try to build stuff on your own throughout this and do as much as you can on your own maybe you watch me do it first and then go try to do it on your own after the fact as I think if you learn everything I go through in this course you can really go and build pretty much anything that you want so without further Ado enjoy the course so we're going to start here at superb.com and I'm going to go to dashboard here at the top right so https superb.com click on dashboard now as you can see I already have a project in here but what I'm going to do is I'm going to go new project and I'm going to click code ran Solomon as my organization now if you don't have a super base account then you can create one for free and you should be all good to go all right so create a new superbase account go to the dashboard page and then select create new project and then what I'm going to name this is I'm just going to name it watch hyphen list and then for the password I'm of course not going to tell you the password I'm using but I'm going to type in my password here and honestly I'm probably going to delete this project after the fact just so I can kind of share credentials and I don't have to worry about blurring those out and then I can just delete everything once I get this video uploaded for you guys so with that I typed in the password here I'm going to put West us but pick whatever region is kind of closest to you here and then I'm going to click create new project so this is going to get created here after a few seconds there it kind of sets up our project here but now that it has done so what I'm going to do is head over to vs code and I'm going to open my terminal and within my terminal I'm going to run MPX create next app at latest so we're going to create a new template nextjs app I'm going to call this watch hyphen list and then I'm not using typescript to no eslin I am going to use tail1 CSS I'm going to be doing my styles with tailin CSS but I would probably recommend you do these as well now you could do your own Styles if you want I'm going to use tailin CSS because I probably am going to be copying and pasting a lot of kind of styles that I've already written for this project in just to kind of save some time but if you're looking for more practice with Tailwind CSS you can definitely write out your Styles yourself but the focus of this is more so just creating a full stack application working on the kind of functionality of doing that within nextjs rather than focusing too too much on Tailwind CSS but we're going to use app rouer for this and I'm not going to customize the default import Alias so once this is kind of all done here what I'm going to do is I'm going to go file open and then open this project within vs code so I've opened this project up here and now that it's in place what I'm going to do is I'm going to open up my terminal again and what I'm going to run is MPX superbase migration new and then I'm just going to call this watches is what I'm going to call my my migration so this should create a migration you should see it getting added over here and what that is is basically like creating a new kind of uh version of the database here and what I want to do is I want to head back to superbase and I want you to click on SQL editor so right over here and now that I have this open up we are going to basically set up our watch table so our database is going to be super simple superbase will automatically give us basically a table for our users so we don't really need to worry about setting that up but what we do need to set up is a table for our watches because users are going to be able to save watches that they you know potentially want to buy in the future so we need to have a table that represents a watch so this is going to have like the the brand name the model the reference number and that's honestly probably about all we need here so what we're going to do here is is we're going to use a SQL Editor to write the SQL to create this database now it's really not too difficult even if you don't know SQL that great I think that you can definitely understand what we're doing here so what I'm going to do here is I'm going to do create table and I'm going to call it watches and then what I'm going to do here is I'm going to do ID serial and then it's just going to be primary key so our watches are going to have an ID but then we also want to connect a user to a watch effectively so there should be a relationship between a user and a watch so I'm going to do user uncore id yuu id references off. users not null and then from there we're going to have a brand column that is text we're going to have a model column that is also just text we're going to have a reference number that is also just text and then we'll have a created at and it's going to be a timestamp with time zone and the default is just going to be now and then we are also going to do an updated at timestamp with time zone now if you want to copy this from my GitHub I totally understand but we are going to just a few more different things to this here so we're going to enable row level security here so I'm going to do alter table I'm going to spell table correctly watch is enable row level security and then semicolon following that and then after that we're going to also make sure users can view only their watches so we're going to do create a policy and it's going to be called users can view their own watches period on our watches table I'm going to hit a return statement here and then we're going to do for select using off. uid and it's actually just going to be off. you ID excuse me and then we're going to call that and we're going to say equals user ID so we just created a policy on our watches table that the off U ID has to equal the user ID so in this user ID up here it has to equal the ID that the authenticated user has so we can only see watches that are connected to a user ID for the authenticated users basically what we're we're saying here we're also going to make sure that a user can only insert their own new watches update their own watches as well as delete their own watches so I'm going to take a very similar approach here but instead of saying for select here it's going to be for insert for update and for delete so I'm going to go ahead and I'm going to copy this policy here and I'm going to paste it here online L 16 and it's going to be create policy but it's going to be users can add new watches so users can add new watches it's going to be on watches and it's going to be for insert and then it's going to be instead of using it's going to be with check off. uid calling that is equal to user ID and then behind both of these I'm going to put a semiquant and then we're going to do a very similar thing so I'm going to copy the first statement here paste this here but instead of users can view their own watches it's going to be users can update their own watches so just change view with update and then it's going to be for update using so it's going be using this time off. uid is equal to user ID and then we want one more for deleting so we're going to come down here and then I'm going to say create policies users can delete their own watches on watches for delete using off. ID is equal to user ID so this is basically saying only the authenticated user can see watches tied to their user ID so it's making sure that only the authenticated user can see watches for that specific authenticated user so now that we have this in place what I'm going to do is I'm going to click run and then after running this you should see success no rows returned right here in the results next to run here all right so we have successfully created this table within our database which should basically be all we need to do here for SQL when building this application so now with this in place let's go ahead and get started with setting up our authentication workflow so to do this let's head back to vs code so now here within our project at the root of our project here so on the same level as package.json next. config.js Json config I'm going to add a new file and what this file is going to be is A.L file so env. looc and then what we're going to do here is we're going to add two environment variables that are effectively going to connect our project here to our superbase database as well as superbase authentication so what we'll do here is I will do nextcore Public uncore Super basore URL then in equal sign and then below that I will next public uncore Suba base underscore Anon n o ncore key so next public superbase URL next public superbase Inon key and then we're going to go back to superbase here and I'm at my dashboard right now just at my home from here where I'm going to go is I'm going to go to settings and then I'm going to click on API here and then when add API you should see this Anon public right here as well as a URL I'm going to go ahead and copy this URL head back to vs code and then paste that as my next public superbase URL and then once that's pasted I'm going to come back and then next to Anon public here I'm going to copy this as well and then head back and then paste that into my I in on public key right here and that is all we need to do within this EnV file so I'm going to now close that so that has effectively connected superbase to our vs code or our nxj project here but now once that's installed we need to install a couple different superbase packages so I need to run mpm install at superbas slash super base hyphen JS so a super base package is what we need to install there and then once that's installed we also need to install some different kind of helare packages here so I need to install mpm install at superbase slof hypin helpers hyphen nextjs and then when we get get these installed as well but now that that's in place here what I'm going to do is just run mpm run Dev and we're going to start our server here and I'm going to also click the plus icon to open a new terminal so we have our server running here and then just a new terminal right here and then I'm going to go back and I'm going to go to Local Host 3000 here and I'm going to click refresh and we should see just the blanket nextjs kind of template right here here and we do see that now that this is in place we can start to get things kind of set up here for our project and the very first thing that we're going to do here is we're going to set up middleware so middleware is effectively something that runs between a certain process so like if we make a request to a certain URL we might want to run some code on that request before that request completes so we want to run middleware in the middle of like kind of two different pieces of software is effectively what it is hence middleware so I'm going to come back here and in the root of my project here so on the same level as my EMV dolo I'm going to add a new file and that is going to be middle wear. JS and I'm also close my terminal and what's about to come here is going to be some stuff that is a little bit more superbas specific but it should be pretty straightforward here so within this middleware file what we're going to do is import and then I'm going to just do an empty object for now but it's going to be from and it's going to be at superbase off helpers next Jazz and what we're going to import is going to be create middleware client so I'm going to type CR and then we see create middleware client so that's a little thing that I like to do is I first do import empty curly braces and then the package I want to import and then from there I can kind of get that nice code completion from this package here within vs code and I'm using the theme winter is coming just in case you're wondering but I'm going to also import from next SLS server and what I'm going to import is next response so next response and then within this middleware file we need to export a function which is going to be the middleware that we want to run between like two different pieces of software before the kind of a request completes and I'll I'll explain this a little bit more here so we're going to export an async function and I'm going to title it Middle where it's going to take a request and then within our middleware here we're going to say constr is equal to next response. next so we're using next response to basically get a response here and then once we have this request as well as the response we can then use super base so we can say const super base is equal to create middleware client and then we're going to call that function and pass in an object in which we're going to set a request property which is equal to request so we're using JavaScript shorthand notation here to say req is equal to req and then we're going to do the same thing for res so the wre property is going to be our request the res property is going to be the the result of calling next response and then from here we want to get our current authenticated user if we have an authenticated user so what we're going to do is say const and this is going to be data colon curly races user is equal to await super base. of.get user so calling superb. off. User it's going to return a data object and on this data object is going to have a user property so we are kind of using nested D structure here to First destructure the data object or the data property returned from the G user object and then we're destructuring the user property from this data property that we are initially destructuring so we're using nested destructuring to get the user and then what we're going to do is we're going to check if there is a user and do some different redirects depending on if there is a user or not so I'm going to first say if we have a user so if user and the request. next url. PATH name is equal to our home route then we actually want to do a redirect so if they're trying to go to our the root of our application but they already have a logged in user we don't want to allow that because what we want to do is if they have a logged in user we we just want to point them to our logged in watch page we don't want to send them to our root of our application because for us that's just going to be a sign-in page so here I'm going to check if user and request. next url. paath name is equal to just empty SL our rot directory we then want to use our next response and then we're going to call the redirect function on this and we're going to redirect them to a new URL all capital for URL then we're going to redirect them to our watch hyphen list route and then the second argument is going to be the request. URL so our request URL is basically going to be our base URL but we want to redirect them to the watch list path and we will eventually create that route here within our project here as well so if we have a user and they're trying to go to our login page effectively then redirect them to the watch list page and then we're going to do a very similar check here but we're going to check basically if they are not logged in and they're not going to the Home Route then redirect them to the Home Route so we're going to say if we don't have a user and not double at but double and the request. next url. paath name does not equal the homepage and what we going to do is return a next response. redirect and then we want to redirect them to new URL empty slash and then the base URL is going to be our request. URL so with if they don't have a logged in user and they try to ACC access a path name that isn't our login page redirect them back to our login page and then once we are done with that we can just return our response now we also need to decide when we want this middleware or what paths we want this middleware to run on and for us we just want this middleware to run when they try to visit our homepage or our watch list those are going to be our only two public routes so that's where we want our middleware to run so I'm going to do export const config it's equal to an object in which we're going to set a matcher property m a t c h e r and it's going to be an array that has a mty slash as well as a string that is our watch list route so we're basically saying run this middleware when they try to access the homepage or the watch list page and basically do these redirects as appropriate here all right so that should pretty well set up our middle wear here let me just like refresh this page make sure I didn't break anything now currently we shouldn't have a user because we haven't really set any of that up so if I try to go to hyphen watch comma list we should see we immediately get redirected to our homepage which we did see that occur right there and I'll do it one more time so you know I'm not lying if I try to go to watch list here you see I immediately get redirected back to our homepage because that is our middleware running in the middle of that kind of request response cycle before that request completes and it's redirecting this back to the homepage because we at this point don't have a logged in user so hopefully that gives you good understanding of how middle War works and I think you're going to learn a whole bunch of stuff like that throughout this this course so moving forward here we want to start setting up an ability for the user to log in and for our application we are going to use a different technique I have you know a video on authentication with Firebase as well as appid as well as superbase where we do just basic email password login but what I want to show you in this tutorial is how you can actually use a magic link and this is awesome and I think you're really going to like it so let's head back to vs code here and what we're going to do is add a new component for this so I'm going to exit middleware DJs within my app directory here I'm going to add a new folder and this folder is going to be called components and then within our components folder we're going to create a component called off form . jsx and for this off form we are going to have to install a library for it and it's going to be another kind of super based Library so we're going to run in our terminal here mpm install and this is going to be at supera base SL offen UI hyphen react we're going to install this package here and then after that's installed we're going to set up this component now this is going to be a client component so at the top of this file it's going to be used client and then here if we're going to import and what we're going to import is off and it's going to be from and it's going to be from off UI react so super base off UI react and we're importing the off component and we're also going to import create client component client from superbase off helpers nextjs so right there and I'm just realizing that I don't really need to use that curly brace trick that I use it's kind of giving me really Co completion right here um sometimes I use the curly Beres trick and I'm kind of used to doing that because when I'm creating bigger projects I'll kind of run out of memory so I won't get that completion right away but this is actually working just well so I might kind of move forward with that the rest of this project in case you're wondering why I'm not using the kind of curly braces thing that I do but what we're going to do here is export a default function it's going to be called off form and then what we're going to do here is I'm going to say onst super base is equal to create client component client and then we're going to call that function and then from here all we need to do is return and I'm going to return our off component here but we're going to add some props to this component so first off we're going to set a superbase client prop to super base so this is going to be the basically the connection between our project and this off component we're going to set a viewr and this is going to equal magic uncore link so it's going to be a magic link component and then we're going to say Show links and that is going to equal false and then we're going to say providers and that's just going to be an empty array and then our redirect here which we will make this in just a second here but we're going to say our redirect 2 is going to equal HTTP colon SL slash and it's going to be Local Host colon 3000 and then it's going to be for slash off for SL call back so it's going to redirect us to logos 3000 slof SL call back now we are going to need to create that in just a second but we're also going to add one more prop here I'm going to do appearance and this is where we're going to add some different kind of styles here so we're going to set a theme and it's going to be equal to dark cuz our kind of uh components are all going to be dark theme and then for our button here it's going to be set to class name and this can be Tailwind CSS classes so this is going to be BG hyen white hyphen 400 the text we are going to make it gray and 900 and then on Hover we're going to make it a background of gray 600 just to kind of change it just a little bit and then below button we're also going to say input and then add a class name and then for our input it's going to be background is going to be gray 700 border it's going to be gray 600 and it's going to be text white so just adding a few kind of styles there we won't manually write out the styles for everything here but since that was pretty quick we'll we'll just kind of leave it at that but now we want to add this all form to our login page so I'm going to go to our root page.js and I'm going to rename this to jsx for better code completion here and not jsz JS X here and then for this component what we're going to do is remove everything currently within the return statement so it's just an empty return statement and also remove image and then what we're going to do is Import off form from components slof form and then here we're going to have just a wrapper div and then within that div we're going to have another div and then we're going to have each one and this is going to be welcome to watch list the name of our application and then below that we're going to have a paragraph and then we're going to say your personal space to carry and manage a wish list of your favorite watches sign in to create view edit and delete watches from your wish list now I'm not totally sure if wish list is one word two words but we're going to leave it at that feel free to look that up and verify that I'm not losing my mind but we're also going to do a div below that paragraph tag and that's where we're going to render the off form now this is going to look pretty ugly and let me just head back to loc Co 3000 and verify that so this looks nasty so what I'm going to do is now add some Tailwind classes to this it's going to be a decent amount so I'm not going to manually write all of them out but feel free to go to my gith repo go to page. jsx within my app here the root page copy and paste these Styles in if you want or if you also want to kind of do what I did to create this project just copy and paste this HTML here paste it into chat gbt and be like hey style this rack jsx here using Tailwind CSS and you can kind of give it a theme to follow like you know make make it a black and gray color scheme or something along those lines so do that or just copy and paste the Styles I have but I'm going to to do that and then I'll see you in a second so I now have all this in here and I realized I used just a little bit different copy in like the project that I created to you know figure all this out um beforehand and that's another thing to note too is like I I create these tutorials beforehand just so it goes more smoothly when I create it for you guys so if it feels like you know I I know every little thing here with this project it's because I already kind of built this out and tested around and ran into issues so don't feel bad if like this feels like a lot because you know it's it's not my first time creating this so just wanted to you know be transparent about that as well but this should look a lot less disgusting and it does I actually think that this looks uh you know this might be a little bit large maybe something like my grandma would need but you know it it looks fine it's it's good enough for the sake of this project to look pretty good so what you can see here is eventually I'm going to type in my email here click Send magic link I'm going to go to my email I'm going to have my magic link I'm going to click on it and then it is going to take me to my website but I'm going already be logged in but to do that we do need to follow a few more steps here so the first one here is notice how in my off form we set our redirect to locost 3000 off callback and if you go to deploy this app make sure that you change this or else the redirect wouldn't be right you would need to use some sort of like base URL based on you know whatever you configure in deployment here but ours is going to be for/ off/ callback so what we're going to want to do is we're going to want to create a new route here that is going to be within an off callback folder So within our app directory I'm going to create a new folder and it's going to be called off and then within my off folder I'm going to create another new folder and it's going to be called callback and then within my callback folder I'm going to create a new file it's going to be a route. JS so this is how we create a route Handler within a nextjs application and then here we are going to import create route Handler client from superbase off helpers nextjs and then we're going to import cookies from next headers and then we're going to import next response from next server now we need to export an async function we're going to handle a get request here it's going to accept a request and we're going to enter the body of this function but here we're going to say const cookie store is equal to calling the cookies function from next headers and super base use this cookie based authentication within nextjs and the main reason for that is to handle server and client components because we can pass these cookies to the client or the server to check for our for our current authenticated user so once we have our cookie store we say const super base equal to create route Handler client and we're going to call it but we're also going to pass it an object and as a property on this object we're going to set cookies and then for our cookies property we're going to point to a function that just returns our cookie store so our return our current cookies from our next headers so that's basically allowing us to get our cookies within our application but then we're going to say const search for AMS and we're destructuring it from a new URL it's going to be our request URL so get our search prams from our request URL in on our request URL when we use our magic link it's automatically going to have a a code search pram so we're going to say const code is equal to search pr. get code and then if we have that code in our search prams which we definitely should we want to await superbase doo. exchange code for session and then pass in our code so when we click on this magic link that we will have within our email it will send us to this this route here and it will have a code in the search pames of this route and then once we have that code this route Handler will run and it will call superbase off exchange code for session we'll pass in the code and we'll return a current session for the user with that email address and it will automatically create this session for us and once that's done we can return a next response. redirect and where do you think we want to Red redirect to well we want to redirect to the only other route that we're going to have which is going to be slatch list and then we're going to set the request. URL as our base URL so just to reiterate here quickly we're basically making this route Handler in which our off form is going to use so we're going to you know click on this off form we're going to click on the magic link and it sends us to this off callback route Handler it's going to have a code in the search prams and we're going to be able to use that code to then create a new session here a cookie based session because we also create this rout Handler client using our own cookie store within our nextjs app and then if all goes well there we are then going to redirect to our watch list page so this should be kind of all set up for us here but before we test this out what I do want to do is within our app folder let's create our watch list route so I'm going to create a new folder and going be watch hyphen list and within our watch list folder I'm going to create a page. jsx file and all we're going to do for now is export a default function watch list and then let's just return in H1 that says watch list and now after we're authenticated here we should be able to see our each one that just says watch list after we finish the flow so let's come back here and let's go ahead I'm going to just refresh for good measure and I'm going to type in my my email address here I'm going to click Send magic link so it says sending link and then it says check your email for the magic link so let me go do that now so right here you should see that I had this email from no reply sub base. confirm your sign up follow this link to confirm your user so I'm going to confirm your mail I'm going to click on that and it's going to redirect me to local 3000 inwatch list and as you can see I now see my watch list page and if our route Handler is working earlier if I try to go back to my home route here it should redirect me back to watch list because I now have a current signed in user so you see I try to do it and then it heads me head sends me right back to watch list so now that that's in place what we should do is well let's first verify that we have a user within our database so I think I can see that within database and I don't see it within watches let me actually go to authentication and yes I do see one user right here so if you go to authentication you should see a user with with whatever email you use for your magic link so pretty cool right like I think that's a very cool way and very easy way of allowing someone to sign in it's like hey just give me your email we're going to send you this link click on it and you're all good you don't need to type in a password none of that which is pretty dang cool if you ask me so now that that's in place what I think makes sense now is we should probably set up this watch list page a little bit more now we're not going to set up all the functionality yet to like add delete and update watches but let's just kind of set up kind of a skeleton watch page and put in some place holders for those functions so let's just create kind of the UI for it and then let's also create a sign out function so the user can actually sign out because currently they literally could just see this page and they can't go anywhere else so heading back to vs code here what I want to do is go to my watch list page. jsx and for now let's just kind of skeleton out what what we're going to want here so I'm going to remove my each1 and instead I'm going to return a div and then a div within that div and then another div with that div and then it's going to be in H1 and let me move that to a different line here and this is just going to say watch list or it could even say maybe my watch list I don't know but we'll kind of put that in there for now then we're also going to want to add maybe a sign out button to the top of this page as well so we're going to do a form and the action is actually going to be a URL that we're going to use to sign out so I'll explain this all in just a second but it's just going to be for slof SL sign out and we will create this in just a second but we will set the method is equal to post and within our form all we're going to do is add a button that is going to be of type submit and it's going to say sign out so we now have an H1 with a button of type submit this sign out now below this form we have a closing div but then below that we are then going to have basically a watch form right here in which a user can input the brand model and reference number and submit a watch but this is going to be a separate component that we're going to create so for now let's just add watch list the component and within our components page let's just do a new file and I'm going to call it watchlist. jsx and then I'm just going to export a default function and I'm going to call it watch no it shouldn't be watch list it should be watch form my bad so let's change this to watch form let's get watch form and for now let's just return like I don't know paragraph that just says dot dot dot watch form and we'll fill this out here a little bit later but now within our watch list this should not say watch list right here this should actually just say watch form and we should import that from components watch form and then below this watch form here we're going to have another div and then within this div this is where we're going to render out our watch list now currently we don't have any watches to map over So eventually we're going to get our watches from our database right now I'm just going to say const watches is equal to an empty array so just a blank empty array here and then within this div this is where we're going to map over our watches and return all of them within this page so we're going to say watches do map and then it's going to accept a watch and then within this return statement here and I'm actually not going to use curly braces I'm just going to use a return straight away we're going to render out another div and this div is going to have a key that is going to be equal to watch. ID and then we're going to add some class names here in a second but for now within this div we're going to add in each one and this is going to be our watch. brand as well as our watch. name within that each one and this actually probably makes more sense to be like an H2 here and an H2 here and then below that what we're going to do is we're going to show them the watch brand as well as the model but now we need a way for them to edit as well as delete a watch because they're going to be able to add watches update the watches they've added delete them so on and so forth so we're going to add another div here and then within this div this is going to be a form in which the action eventually this is going to be a server action that we use here but for now just call it delete Watch we will replace this with a function here and just just a little while but within this form what we're going to have is an input and this input is going to be of type it's actually going to be a hidden input and this is just so we have some extra data for our delete Watch server action I know this is a lot right now but just follow with me for a second I will explain all this in the future when we go to implement this we're really just skele this out a little bit but now I'm going to do name is equal to ID and the value is is going to equal watch. ID this is important because when we call this delete Watch server action we want to have the watch ID that we want to actually delete and we're going to set a button and the type of this button is going to be equal to submit and this is just going to be a delete button then just outside this form we are going to have another component but this component is going to be an edit watch component and the purpose of this component is going to be that when they click on this component it's going to pop up a model that has all their watch information they can edit and then basically make a patch request to our database to change that watch so I'm going to type in edit watch and then it's going to have one prop that is going to be equal to the watch and then we're just going to close that component and then as we did before I'm going to go to components new file and it's going to be edit watch. jsx we're just going to export a default function called edit watch with one prop that is going to be a watch and then for now let's just return a paragraph that says dot dot dot edit watch component all right so that is that is it I know that might been a lot but we really just kind of wanted to skeleton this out a little bit but now I do want to add some styles to this page so I'm going to go ahead and copy and paste those Styles in here you can use the same approach of chat GPT earlier or you can go to my GitHub and copy and paste everything you see over just make sure that if you do copy and paste it over like this will be pointing to an actual function make sure to just make it a string so let me go ahead and I'm going to copy and paste what I see here from GitHub and then once that's pasted in I'm going to just update the the formatting here a little bit so it doesn't look gross and then instead of this being delete Watch just make that a string I also have like you know a comment in here that I'm going to get rid of and since I just got rid of it now it shouldn't be there for when you see this I believe everything now be good but maybe just you know double check if and make sure that this is all kind of working for you but we should have everything that we need we do need to import edit watch here so we're going to import that at the top here from components edit watch if I come back here we should see my watch list and then we just see like watch form dot do dot this will eventually be a form where they can add their watches and submit them and then we'll have the delete and edit button like we have down here but we're only going to see those if we actually have any watches and we haven't got those from the database yet so we're not going to have any watches it's just this empty string or this empty array but right now if I click sign out here it's not going to work because currently signing out it just makes this like request here to off SL sign out which we haven't created yet but we're going to do that now so within the off folder create a new folder called sign out within sign out I want you to create a route. JS file and this is where we're going to handle signing out the user so this is actually going to be very similar to signing in the user so we're going to import create route handle our clients from superbase off helpers nextjs and then from here we're going to import cookies as well from next headers and then we're going to import next response from next server and then we're going to export an async function post it's going to accept your request and then we're going to say con cookie store just like we did earlier is equal to calling cookies and we're going to say con superbase is equal to create route Handler client call that function pass in an object and set the cookies property to point to a function that returns our cookie store and then we're going to say const curly braces data colon cly braces session so it's going to return an object that has a data property that data property is going to point to an object that has a session property and we are destructuring that here but we're going to set set this to equal await super base. of.get session so we're going to get the session here and we're going to say if there is a session then what we want to do is await super base. off. sign out so we're going to sign out of our session and then we also want to redirect them back to our homepage so return a next response do redirect and we're going to do that to a new URL and it's going to be our home route we going to be your request. url as our base path name but we're going to also pass another argument here we're just going to pass a status of redirect so 302 so when they click on sign out right here they are going to make a request to off/ signout which is going to be this route Handler right here we're going to accept the request right within this this post right here we're going to get our current session from superbase and then we're going to sign out of that session and then redirect them back to the home page so if we've done everything correctly here we should be able to come back click on sign out and it should take us back to our homepage here and we see that works and we're not redirected because we no longer have a session and if I try to go to watch list I get redirected back to my homepage because we don't have a session but if I type in let's do a new email Ry at cod. I'll send the magic link and then let's go to that email and then I'm going to click confirm your mail and then it redirects me back to my watch list here if I try to go back to my home route I can't do so because I'm already logged in but if I log out it takes me back to my login page and then if I check my kind of off super base I now see I have two different users Ryan Cod ryan. ryanryan salon. if I want to relog in to my Ryan at let's just do Ryan Cod ryan. again I can just send this magic link again here head back to my email click on log in and then we should see my watch list page so we have successfully connected superbase to our nextjs project here allowing us to add users to our project sign in and sign out so the authentication piece of this project is pretty much done here but now that this is in place let's now start setting up this watch list page to where they can type into a form submit new watches update them delete them and kind of show you how to use basic kind of creates read update and Destroy within our superbase database so back in vs code here what I want to do now is instead of just hardcoding this watches as an array here I think it's time that we now connect this to our database and actually get our watches from our database so to do this what we're going to need to do at the top of this function is is say const cookie store is equal to calling cookies from next headers so this will give us access to our cookies very similar to what we've done before with middleware and our route handlers and then once that's in place we're going to say cons super base is equal to create server component client because we are in a server component right now and this is is going to stay a server component so we're going to call that and then when we call that we're going to pass in an object in which we're going to set the cookies property to a function that returns our cookie store and then now that we have that in place we can get our user session so we can say const data and then within that data object it's going to have a session property and that is going to equal await super base. o.get session so we're going to get our session from superbase and when we call this we are going to destructure data and D structure session within data and this should be an async function watch list so I'm going to go ahead and do that now that we have the session we can say cons to user is equal to session and then I'm going to use the question mark operator. user so our user is going to be a session. user and then below this we can say const data and then we're going to destructure data but I want to name our data to be watches so we're going to set data as watches and then comma eror is equal to await and this is going to be superbase do from and we're going to get data from our watches table and then we're going to dot select call that function we're going to PR in Star so just like the SQL using a star we're going to get everything from our watches table but we're only going to get stuff so EQ and then we're going to call that and then it's only going to be the stuff where the user ID is equal to our user. ID and let me move all these onto a separate line here and then we also are going to give an order to this so we're going to say do order and we're going to order it by brandan name and we're going to set ascending to be true and then I'm going to remove this watches constant so here I'm doing is I'm saying from our superbase connection here that we've created here with our cookie session we want to get the watches table return all of our columns in which the user ID of that table is equal to our currently logged in user and make sure to order those by brand in which a sending is true so alphabetically and then the only other thing that we need to do here is say if there is an error then I'm just going to council. ER air fetching watches so this should return all of our watches from our database so let me go ahead I'm going to council. log watches here we shouldn't have any watches currently because we haven't added the ability but what we should see is that if if I refresh my watch list page then I should just see an empty array here and there should not be an error fetching these watches so let's go ahead and check that so I'm here at my watch list I'm going to refresh this page head back to vs code open my terminal go over here and I do see watches as an empty array so theoretically we have everything set up here to Now read our watches from our database and it's pretty pretty cool that we can do this just like right within this server component here we didn't need to make a like use effect and then make a network request here I can just get these watches right away in This Server component and then render those within this page but now that this is in place what we can do is I can implement this watch form which will allow us to actually add our watches and then once we can add watches we should be able to see them rendered on this page right here and then we need to add the ability to delete watches so we'll implement this delete Watch action here and then following that we will add the ability to edit these watches and then we can go ahead and deploy this this project here so the first thing that we're going to do is head over to watch for. jsx so here it's mostly just going to be a form that we use a server action to add watches so instead of what we currently render right here I'm going to remove this P tag and what we're going to do is add a form so we're going to return a form here and the action is eventually going to be add watch I'm just going to hardcode it as a string right now but within this form we're going to have a wrapper div then we're going to have a label in which the HTML 4 is going to be for a brand and then the name of this label is just going to be brand so this is going to basically be an input where they can input the brand of the watch they want to buy so the input here it is going to be of type text the ID is going to be equal to Brand the name is going to be equal to brand and it is going to be a re ired input We'll add some class names to this in just a second and then we're going to do a very similar thing below this we're going to do another div and it's going to have a label it's going to be HTML 4 model and the label is just going to be model and then we're going to have another input here the type is going to be text the ID is going to be model the name is going to be model and it also is going to be required and then we're going to add one more input here so I'm going to just copy and paste this below but now it's going to be HTML for reference number so they can put the reference number of the watch and then I'm going to put reference number here and then the ID and name are both going to be reference number and then at the bottom of this form we're going to do a button that is going to be of type is equal to submit and it's going to just be add watch so this is going to be our HTML for this page now I'm going to go ahead and add the styles for this page you can go ahead and copy and paste these or you can also do what we've done earlier and ask chbt to style this within Tailwind CSS so I've gone ahead and added these Styles here but now that this is in place what I do want to do is I want to now go ahead and add this server action for this form so when the user clicks on this add watch button we use a server action to basically add this watch to our database so the way that we're going to do this is within my app folder here I'm going to create another folder and it's going to be called serverin actions and within this server actions folder I'm going to create an action that is just going to be add watch. JS and within this add watch server action at the top of the file I'm going to call this use server also going to import and it's going to be create server client component from superbase off helpers and then we're going to import revalidate path from next cache and then we're also going to import cookies from next headers and then we're going to export an async function called add watch it's going to accept form data so automatically when we submit this form it is going to pass us the the form data so all the data with our like names and ID inputs and then here we're going to get the data at the top of this function so I'm going to say constant model is equal to form data. git and it's going to be model and then I'm going to option shift down arrow to copy that down line and then this is going to be brand and then we're going to do form data. brand and then I'm going to do option shift down arrow and then it's going to be const reference number is equal to form data. get reference number so we're basically getting our brand here as well as our model as well as our reference number from our submitted form within our server action and then now we need to connect to our database so we need to do the same thing that we've done this entire time which we're going to do const cookie store is equal to calling the cookies function and we're going to say const super base is equal to create server component client we're going to call this P it an object in which we set the cookies property to point to a function that returns our cookie store like usual and then we're going to say const and then destructure data and then destructure session within our data object is equal to await superbase do.get session so we're going to get a currently active session here we're going to say const user is equal to session question mark. user to make sure there's a session then we want to do a quick check here and just say if not user then council. eror and say that user is not authenticated within ad watch server action and then we'll just do an early return here but if we do have a user then what we want to say is const data common error or comma error is equal to weight I'm going to do super base and then on the next line I'm going to say dot from watches so get our watches table and then I want to dot inert we're going to call the insert function and we're going to pass it in Array and within this array this is where we're going to add an object that has our model model is going to equal our model our brand is going to equal our brand and then our reference underscore number is going to equal our reference number and then our user uncore ID is going to equal our user. ID and then from here we're going to check if there's an error then we want to let me scroll down further console. eror and I'm just going to say that there is an error inserting data and I'm going to just do a comma and then councel log the error as well and then we'll just do an early return here but then if that's not true if that is successful then we're going to call the revalid path function and the path that we want to revalid is our watch l list and then we're just going to return a message that has success so to kind of take you through what we just did there we created a server action that first gets our brand model and reference number from our form data then we can create a server client here that's going to have our session if we don't have a user we're just going to early return and councel that eror but if that is not true then we are going to call this superbase function to insert our model brand and reference number so a new watch within this user ID or this user's table and then if that does not air here we're going to make sure to revalidate our watch list page so we actually see our updated watch within our page and then if we go back to our watch for form instead of hardcoding add watch here what we need to do is actually just make this our Adat server action so now I think we have everything in place here to test this out so if we come back we now see we have a form here with brand model and reference number and we can try to add a watch so I'll do a Rolex subar ER this is maybe one of my favorite watches of existence I don't know the reference number so we'll just do 1 2 3 4 and then I'll click add watch and what you see added here is a Rolex submar it has a delete button and an edit watch component so it looks like we have successfully added this watch here with our server action and then we map over our watches and render out our watch brand and watch model with a delete Watch button here as well as our edit watch component which is what we see here and then if I look at my console I see the added watch here for this user so we have successfully used a server action here to add this watch and if I don't add this revalidate path here let me comment that out and let's add another watch so I'll do a Rolex Daytona or naming a bunch of watches I can't afford and we'll do one two three three I'll click add watch and what you see is I don't see it immediately but then if I refresh my page I do see it and that's why we need that revalidate path because we need to make sure to clear the cashier and revalidate our watch list page so now that I reinstated it here let's do an Omega we'll do a CMAs and we'll just do one two 2 one and now we'll click add wash and we see it gets added right away without me needing to actually go ahead and refresh my page so we have successfully added the ability for a user to go ahead and add a watch here which is pretty dang cool but now that we have this in place let's go ahead the ability to delete a watch cuz right now if we click delete nothing's going to happen so we need to come back here and we're actually going to do this with a server action because here within my watch list page we see we have a delete button which is just a form that's going to call this delete was action so to do this within my server actions folder I'm going to add a new file and it's just going to be delete watch. JS and then within this delete Watch component it's actually going to be pretty similar to what we did to add a watch so I'm going to go ahead and I'm going to copy my Adat file control command C and then command V but then we just need to structure this a little bit differently so for our form data at least for the name of this it's going to be delete Watch instead of add watch and then for the form data instead of getting the model brain and reference number we're just going to get the watch ID which is going to be form data. git and it's going to be the ID and then we're going to delete the brand as well as the reference number and then from here we're still going to have our cookie store we're still going to create our super base create server component client and then we're still going to get our session and we're still going to get our user if we don't have our user I'm going to say user is not authenticated and this should actually be within so let me go change this in my ad watch to within but user is not authenticated within the delete Watch server action and then we'll return but now here in instead of inserting watch what we need to do is say cons and we'll just say const erir is equal to await super base. from watches but instead of calling insert we actually want to call Dot delete and what do we want to delete well we want to delete the watch that matches so we're going to call it delete. match in which we'll pass in an object and and we'll see the ID is equal to the watch ID and then the user ID is also equal to our user. ID so it's saying delete this watch with this ID or the user that is currently logged in and then if there's an error I'm going to say error deleting data and then we'll councel log the error but if it is success ful then we will revalidate the the watch list path just like we did earlier because if we don't we're not going to see the updated list with a deleted watch and then we'll return a message of success here so this should be our server action all set up here and now within our watch list page instead of the hardcoded delete Watch we can just do delete watch as our server action and make sure that's imported up above here so now if I come back we should be able to successfully delete let's delete the Rolex Daytona and we do see it gets removed from our page let's delete the Submariner it gets deleted but we really like the Submariner so we need to go ahead and add that back to our page here and we can see we get it added right back so hopefully this shows you how powerful server actions are here we're we're doing like a lot of this just from the server and we're validating our paths here and this can really improve performance and you know prevent a lot of network requests and a lot of complexity because we're able to just make all these requests from the server here so pretty cool we now have the ability to get over our watches from the database we can create new watches and we can also delete watches so really the final piece of functionality to implement here is how to edit a watch and we're going to do that by implementing our edit watch component so if I head back to vs code here we have this edit watch component that accepts a watch so all we need to do to finish out the functionality here of creating reading updating and deleting watches is this edit watch component so let's go within that component and what we're going to do here is we're going to create a component where if they click on the edit watch button we're going to pop up a model that has basically our watch form refilled in which they can edit the information they added and when they click on Save it's going to update our database now for this since the user is going to click on this button and pop out a modal so there's going to be this user interaction here we are going to make this a client component so it's going to be use client at the top now we're still going to use server actions for this because we can use server actions within client or server components especially the way that we structured server actions so I'm going to import use state from react and eventually we're going to also import and update watch server action we'll hold off on that for a second but here at the top of this function we're going to say const show model comma set show modal is equal to use State and we'll initialize it to false and then below that we're going to say const form data comma set form data is equal to use State and then we're going to initialize this to the data that we've already passed in to this edit watch so we're going to set the brand that is going to be our watch. brand and then we're going to set the model is going to be the watch. model and then the reference number is going to be the watch. reference number so within this page we render over all of our watches and We R render out this edit button for each watch we pass the watch in as a prop to this edit watch component and we accept that prop here and we initialize the form data for this edit watch component as the this watch's brand model and reference number number and then here we are also going to say const handle change is going to be a function that accepts an event and all we're going to do here is we're going to set our form data it's going to be all of our previous form data but then we are going to set the event. target. name to the event. target. value so it's basically taking all of our form data spreading that into our new form data but then it's setting the new input that is change it's going to set the name of that input to the value of that input and then that is all we're going to do here and now we can start rendering out kind of the the HTML here so what we're going to return is a div wrapping all this but then we're going to render out a button and the onclick of this button is going to be a function in which we set show modal to be true and this button is just going to say edit for them to edit the watch and that's going to set the show model true in which we are then going to show this model so let's first skeleton out the form that we want to show here but then I'll add the Styles here in a second so I'm going to do show modal and return this so if show modal is true I want to return our modal here and it's first going to be a wrapper div and within that div we're going to do another div and within that additional div we're going to render a span and this span when clicked we are going to set our show modal to false and we're are going to render out a kind of X component so the the multiply symbol so this is going to be a little X that we render out at the top of the model and this impan times semicolon is just us rendering that symbol out within HTML and then below this is where we're going to render out our form the action for now is going to just say update watch but eventually we're going to add a server action here to actually update our watch and make that update request to our database and then we're going to set in onsubmit here in which in this onsubmit we're basically just going to set show modal to be false we're no longer going to show this modal and then we're going to run our server action so as the first input here it's going to be input of type hidden in which the name is going to be ID and then the value is going to be our watch. ID and this is basically going to give us the ability to within our server action to access the ID of the watch that we want to then go ahead and up but then below this we're going to do a div and then we're going to have a label which the html4 is going to be brand and then the within that label is just going to be brand and then we're going to do an input that is going to be of type text and the ID is going to be brand the name is going to equal the brand and then the value so it's going to be controlled input the value is going to be are form data. brand and let me move this all to a second line here in the on change is going to be our handle change function and we'll add some classes here in a second and then I'm going to copy this div here here and paste it below and now instead of our brand it's going to be our model so we're going to do model this is going to be model and it's going to be type text but the ID is model the name is model and it's going to be form data. model and then we're going to do that one more time but it's going to be for our reference number so here it's going to be reference number the HTML 4 is going to be reference number and then the ID and name form data. reference number and then below this D is where we're going to do a button that is going to just be update watch and then it's going to be of type is equal to submit so when they click on this function that should trigger our server action here that we'll create that will then update this watch but what I'm going to do now is I'm going to go ahead and add all of the class names I want to to this HTML and you can copy and paste mine from my GitHub repo or you can go ahead and paste this in at Chad GPT and kind of work with it yourself and try to get Chad BT to make you this kind of popup model so I've added all my Styles here and I think this should be pretty well set up at least from the UI standpoint we still need to implement the server action but let's go ahead and check so we see delete and edit here let's click on edit and I see update watch is not defined that is because when I copy and pasted my Styles I forgot to turn this back into a string so let's come back let's click edit again and now I see Halle submit is not defied and that is because in my copy and paste I pasted a handle submit in which in reality we can just pass in an inline function here that is set show modal and it's going to be false so let's come back again do it one more time and now we see it is pre-filled with a brand the model but we don't see reference num so let's come back here and then so this instead of watch in camel case reference number it's actually going to be reference uncore number because that is how it's returned from our database so let's come back let's look at this again and now we do see the reference number so now we can update this and we should be able to click update watch and then see our updated watch in our list here so now let's come back and let's create another server action so this time around it's going to be a new file and it's going to be called update watch. JS and then I'm going to move this over a bit let's go to Adat here let's copy this entire file and let's paste it into update watch because it's going to be also pretty dang similar to what we've done before but at the top here instead of Adat let's call this update watch it's going to accept our form data it is going to accept a model brain and reference number just like what it does here but I'm going to also do option shift up arrow and I'm going to say const ID is equal to form data. ID because we need the ID of our watch and then we're going to do the same thing create our cookie store create our connection to superbase we're going to have our data in our user session data if not user we're going to say user is not authenticated within our update watch server action and then here below we're going to say from watches we're going to instead of insert we're actually going to call update and then instead of passing an array we're just going to pass an object so remove the array and just passion has an object here and then we're going to set the model is going to be our model the brand is going to be our brand the reference number is going to be the reference number but we're not going to pass the user ID here we're actually going to do dot match and then this is where we're going to pass an object in which the ID is going to be our ID and then the user ID is going to be our user. ID so we're going to use this super base function that gets our watch table it's going to update the model brain and reference number for the watch that has this ID here from our form data and it's going to be only the watch with that ID for the logged in user and then if there's an error I can say error updating data we do need to revalidate our watch list so we see the change occur and I'll return a message of success so as you can see once we kind of get the pattern for one server action it's actually all pretty dang similar here so now that that's in place let's go to the edit watch component here so I'll open components I'll go to edit watch and then instead of hardcoding this action right here what we can do is update watch which is going to be this server action right here so now with all of this in place I should be able to update these watches in our list so for the Omega C master I should be able to edit and I'm going to keep this as Omega but I'm going to do the Omega C Master no time to die version then I'm going to click update watch and we see this gets updated as the Omega C Master no time to die then for my Rox a mariner let's do the Rox a mariner but the no date version Now update this and then we see it is updated so we have successfully added our watches deleted them updated them and we are also reading our watches in this watch list and we also have our user authentication here now I kind of forget what user I'm signed in as let me let me go ahead and check that real quick so let's go to our watch list here I'm not going to council. log watches anymore but I will counil log my user and I see that it's Ryan at COD ran. is my user I'm going to delete this counsel. log and let's just make sure that I can indeed sign out and then let's relog in at Ryan Cod ran. so I'm going to send the magic link I'm going to click log in and then I do indeed see my watch list with my two watches that we just kind of created and up dated here so everything looks to be working correctly here we now have a functioning app where we can create read update destroy from our superbase database we can log in with different users and we we have a full functioning app and like honestly if you understand everything we've done here you can build so many different applications with just having some sort of database some sort of like user interface which we have here and then also having some sort of authentication which you've learned in this entire video but now the final step here is to now deploy our application so to do this I'm going to first go add this project to GitHub so I'm going to go to github.com and I'm logged into my GitHub account here I'm going to click the plus icon to create a new repository here I'm going to name this watch I list it's going to be public and I'm going to create this Repository and then I'm going to copy this get remote ad origin and then the URL right here now I'm going to come back and in my terminal here my non-running terminal I'm going to clear this and I'm going to say get status and I'm going to add all this so get add period and I'm going to do get status I see all my files here I'm going to get commit add watch list Pro we still might need to make an update here which I'll cover a second and then I'm going to get remote ad origin so what I just copied from GitHub and I'm going to call get push and I'm going to get an error because I need to get push and do this command so I'm going to copy and paste that and now if I refresh my GitHub I should indeed see my watch list project here which I do so now that this this is added GitHub I can now go to versel and deploy this project now we are going to have one issue here but we'll uh we'll cover that in a second at least I think it's going to be an issue but now I'm here over at versell decom and I'm logged into my account here if you don't have a versell account you can go to versell decom and you can connect it to your GitHub for absolutely free so you can go ahead and do that now if you haven't done that but connect to your versel to your GitHub you should see it automatically if you can't find it just Google quickly connect to verell the GitHub it should be super super easy to do but once you've done that click on this little triangle here at the top to come to your dashboard and then we're going to click add new I'm going to do project and then the project I'm going to do is I'm going to import from a git repository so what we just added to GitHub and I'm going to do watch list so I'm going to go ahead and import that now now we do need to do a couple of things here so for our environment variables we do need to add our two EnV keys so let's go back to our vs code here let's go to our dmv. looc and I'm going to go ahead and I'm going to copy my next public superbase URL I'm going to come back I'm going to paste that in as the key and I'm also going to grab this value and I'm going to come back I'm going to paste it in as a value I'm going to click add and now that I've added that I'm going to add another key in value here so I'm going to grab next public superbase andon key paste that in here come back and then I'm going to copy this entire key here come back paste it in as the value and click add so we've added those and now I'm going to go ahead and deploy although we still are going to have one issue here so the issue that we're going to have is I'm going to go command shift F and I'm going to search for local host coin 3000 and as you can see in my off form here we still have the redirect set to http coin Loos 3000 slof callback so we have hardcoded this in here now what I think is going to happen here is I think that this is going to break because in our deployed application once this finally finishes deploying it's going to give us a new URL that is no longer going to have this in place it's going to be something other than Local Host so to fix this I might be able to just pass in a relative path here as like for slof for SL callback but I'm not sure that's going to work but we'll we'll go ahead and wait for our application to be deployed and then we'll kind of play around with making sure that this does indeed work correctly and we can indeed add users to our deployed application so it looks like congratulations you just deployed your project to versel and when I click on this we see that my base URL is now https coed watchlist Plum verela so let's go ahead and add or try to log in here I don't think it's going to work so I'm going to do my code ride in here I'm going to send the magic link and it it sends but then when I click on l in here you see it takes me to Local Host 3000 but this isn't going to work because my my app isn't at locost 3000 anymore so it's actually at this URL so I'm going to go ahead and copy this deployed URL here and I'm going to paste it right here so now it's going to be at https co/ watchlist plum. bell.app slof SL callback so we're going to past this in here but I also need to deploy this change so I'm going to do get add get commit DM update base URL then you get push and this will Deploy on versell automatically here in just a second and I think this is the only place we use locost 3000 I do have locost 3000 in my readme but we don't really care about that so I've deployed this change let's go back to verell here and I should see if I continue to the dashboard here I can see that it is currently building right now with the commit of update base URL so it looks like it's already done building here so let me refresh it looks like everything's good so I'm going to click on this and now let me go ahead and try to do this again so Ryan Cod r.o I'm going to send my magic link to send I'm going to click on it here and now we do indeed see the watch list so thank you so much for checking this out it looks like everything is indeed working here so really with everything that you have learned in this tutorial you have learned how to create read update and Destroy from our database add authentication and create a full stack nextjs application and deploying it as well so thanks so much for checking this out and I will see you in that next one
Info
Channel: Code Ryan
Views: 2,495
Rating: undefined out of 5
Keywords: coding, programming, frontend engineering, code, software engineer, javascript, web development, next js, react js, next js 14, supabase tutorial
Id: 5xu_KH8QSk4
Channel Id: undefined
Length: 99min 0sec (5940 seconds)
Published: Mon Dec 11 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.