Transcript for:
Full Stack Tutorial: Devinder Application

hey everyone how's it going I have another full stack tutorial which I want to share with you all today hope you guys are interested basically in this tutorial I'm going to show you how to build out devinder which is a service that allows other developers to find people to pair program with maybe you're stuck on something you want to share your screen and other developers can kind of filter based on tags and join and kind of watch you as you're trying to code maybe work with you along the way um let's just demo what we're going to build and I'm going to walk you through some of the technology that going to be using in this so first thing we got some dark mode we got some light mode pretty cool let's go ahead and sign in we have authentication that's set up with next off I just go ahead and sign in with my Google provider and once you're signed in you can go and create a new room so that other people can join you so let's go ahead and create a room I'm going to go ahead and say devinder the description is going to say a side project to help developers find other people to pair program with for the get repo let's just go ahead and grab my Dev finders project repo and then down here for tags I'll say typescript nextjs we'll say drizzle omm we'll say next off and Shad CN those are some of the tools that we'll be using in this tutorial so smitth that that room will be created and now if I go and switch this from OBS to my face we have live video chat with screen sharing right down at the bottom we can see all the participants who are in this chat and also we can share our screen we can chat with her microphone let me just go ahead and join with another tab over here so I am logged in on another incognito tab with a different user I'm going to browse and I can see that that Dev room is now popping up so we see devinder over here so one feature is we have the ability to search for rooms based on tags so for example I could type in typescript and press enter and that'll only show me the rooms that other people are in where they're kind of working with typescript or Shad scen or whatever we can also get a link to the GitHub repo so clicking this will take us to the repo I can learn more about the project that they're working on maybe look through their issues see if I can maybe contribute with them I can go and see my own rooms which this user doesn't have any let's go back to browse I'm going to join this room and we'll have two users go ahead and allow my camera awesome so now we have two people in this chat room and the cool thing is is that one user could potentially share their screen and I can see that so let's just go ahead into my other tab I'll just have that user share the drizzle orm Tab and as you can tell I can see the screen that they're sharing right over here right so they could basically Live code with me they could share their code I could talk with them and I could potentially full screen this if I wanted to and actually get a better look at what they're doing escape to get out of that and you can also edit a room so clicking here will take you to an edit page I can go ahead and just give a I can go here and just edit this and I'll click submit that'll take us back you can see that update happens and we also get a nice toast that told the user that the edit happened and then we can also filter by tag so for example this room has tags of nextjs if I go ahead and click on one of these tags it'll automatically take us back to our browse page with our filter set up inside the input box and now we'll see all the rooms that are also working on node content and that's basically what we're going to be building in this application finally we have the ability for a user to sign out or delete their entire account which will clean up all their rooms and delete that data which I'll just go ahead and do that I'm going to delete my account and we should see it just go ahead and wipe out all the data that was associated with that user and then finally this is deployed somewhere so I'll kind of walk you through how this is all deployed out so let me talk real quick about the tech that we're going to be using first of all I want to give a special thanks to our sponsor which is stream go to getstream.io and we are going to be using their video and audio products this has a bunch of built-in react components iOS Android JavaScript Etc and honestly with very little effort you can get that screen sharing capabilities with just basically importing a couple components and you'll see that as we kind of build out this tutorial so definitely a really cool Service as actually super impressed with how easy it was to get the streaming set up second thing we are going to be using nextjs with server actions and react server components a little bit we're going to be using Shad CN for our components I love Shad CN I think it's very easy to build a UI with shad CN for the OM we're using drizzle orm and connecting to a postgress database which is running locally in a Docker container and then also when we go to production we are going to be using Railway I will say Railway is not a sponsor of this video I just think their service is pretty good but they are a paid service so if you want to go to production you may have to take out a credit card but it's very easy to spin up a postrest database and also deploy your nextjs application and then finally we're going to be using next o for the authentication of this application if you're interested in any of the code it is found here in this URL I'll put this in the description link below other than that that's about everything we're going to be building in this application I hope you guys enjoy watching if you want to learn more about nextjs or any of the technologies that I just mentioned let's just go ahead and jump into it and have some fun all right so let's go ahead and get started the first thing I usually do is I'm going to make a repository and let's name it Dev finder so Dev finder is the name of our application and what it say MIT just go aad and create this repository and then we are going to clone it down so I'm going to click on this code button I'll click on this copy to clipboard URL now I have um SSH key set up if you don't you might have to do https but I just go ahead and copy this my clipboard and then in my workspace I'm going to say get flown and go ahead and cl that repo out and then I'm going to open it up so we can start coding on it so we are using nextjs so the first thing I'm going to do is npx create next app at latest just go ahead and do that in this directory that'll go ahead and ask us a couple questions I'll just use the defaults for everything all right and now that that is done let's just make sure it works so npm run def that should spin up your nextjs application on Local Host 3000 you see this page you know everything is working correctly so some additional setup we're going to do is I like using Shad CN for all my components I think it's a really great component Library so let's go and go to the installation guide let's go to nextjs and let's just go ahead and start at number two because we already ran number one so let's just go ahead and copy this we're going to run that in another terminal over here we'll zoom in one more and we're going to use the default so I'll say yes we want CSS variables we want the Slate based color and we should be good so to verify this is working what I'd recommend doing right off the bat is just go ahead and set up dark mode they have a nice getting started guide about dark mode so we're going to install next themes which is a library that you can use to kind of set up dark mode and most applications you should probably have dark and light mode it just it's better user experience so it's you might as well just do this right off the gate right so let's go ahead and make a components theme provider over here I'll say Source components theme provider. TSX paste that code in and save it and then let's go to app layout so let's just go ahead and copy this let's find app layout man P can do your fuzzy searching and then we're going to go ahead and just import that theme provider like they ask you to and then we're going to wrap our code right here with the children let's just go ahead and wrap that in the theme provider like this now make sure I put it inside the body now something else you sometimes have to do is you have to add this the suppress hydration warning on the HTML so adding that and then we could try adding a mode toggle button so the way you do that is you go to the code tab we're going to copy this and then we're going to go to components over here and we'll just say mode hyphen toggle PSX paste that in make sure this is good so this does depend on a Jaden button in a Shad scen drop-down menu so one thing we haven't done yet is how do you install these other components right Shad SC is a little bit different everything is not just given to you out of the box you have to install these things individually so if we go to the button component over here we can actually just run this command goad and copy that and then I'm going to run it in my terminal and that will grab the button code and put it in your component's library as you can see over here we have a button inside this UI folder and we should be good to go and notice that now we don't have a typescript error here because it found that component we were looking for so we also need a drop down so let's go over here drop down menu copy it uh paste it in and that's basically the gist of shad and you want something you just go ahead and install it and you just start using us so now if we were to go back to layout the reason I'm doing this is because I want to go ahead and put like a header here so let's just go ahead and say a div um for now we'll come back and we'll abstract this into like a reusable header component but I'm going to go ahead and say just uh mode toggle or what do we call it yeah it's called mode toggle let's say mode toggle import that save it and now let's hope that everything works fine and refresh the page see if it shows up so click it um and notice that we have light mode we got dark mode awesome now I like to keep it as system and my system is dark mode so we will probably keep this um during the whole tutorial but just keep in mind as you're adding new components and doing new pages it's always good to double check that when you switch to light mode because there's still a lot of people who use light mode that it looks good all right so we've made some progress um what I like to do throughout my tutorials is I like to commit small chunk size commits throughout the entire process so let's just go and say um initial next setup in Shad CN with dark mode now the reason I do this is that you can actually follow along and if you're good at git you can kind of go back through the commits and view them as they're changing over time okay so now if I go to my commits we have our first commit here you ever want to go back and kind of check that out you can just go ahead and click on it and see like what did I add at that part of this tutorial so the next thing I want to get set up is some type of connection to a database typically you need to use an orm or if you just want to connect to your database directly with SQL statements you can do that I like using something called drizzle omm there's also Prisma there's also other orms you can use but I think drizzle is a nice Middle Ground between like not giving too much abstraction but also giving giving just enough abstraction that you can become very proficient at it all right so going to the get started we're going to be using postgress and I'm going to use postgress DJs as our driver you can connect this to basically multiple different types of databases and they have different drivers you can use if using my SQL or postgress or sqlite basically just read those documentations but I'm going to use postgress and the way you kind of get this started is you run impa install drizzle orm and this postgress package let's go ahead and run that there we go and then also I'm going to install drizzle kit as a Dev dependency and we'll talk about what drizzle kit is in a bit but let's just go ahead and get that set up so following their documentation what you can do is you can just go ahead inside a source directory I could add one called DB and we'll make one called index.ts let's go over here and let's just copy this starting code and let's kind of look through it a little bit make sure we understand what's going on so this is going to import the drizzle or M it's like a library we use to connect to the database and easily query and store data there's also this migrate function which we won't worry about just yet and then we're going to bring in postgress which we should already have installed and the migration client we don't need right now but what we do want is the query client also this DB object so I'm going to make sure I export DB over here and all this other stuff um we're just going to get rid of her right now and one thing you'll notice is that there's like this URL over here this is the connection URL that you're going to need so that the drizzle orm knows where your database lives and so if you were to be renting a postgress database from like Railway or super base that's the URL you'll gr you're going to point in in this tutorial I am going to be using Docker to set up a local postest database and the reason I do this is because often these services that give free and hobby plan tiers you never know if they're going to not use those hobby plans anymore so I want my tutorials to be resilient to these third party Services getting rid of their free plans so we are going to be using Docker it's not too hard to understand and learn so keep that in mind so once we have this index.ts stuff set up what I want to do is I want to create a Docker compose file so I'm going to say Docker composed. EML and you're going to have to go and read up on how to install Docker on your machine and Docker compose I'm not going to walk you through that or if you just want to install post Crest directly onto your machine that's an approach too this is where I kind of recommend that you go and figure this out yourself or just find a service that provides you a hobby tier postest database but I already have a Docker compose yamamo file and I'm going to paste this in here and we're going to go ahead and rename some stuff so I'm going to rename this to devinder and what this Docker composed file does is it kind of defines what containers it needs to spin up when you run Docker compose up so in our case it's saying I need you to spin up a postgress database on this port fact let me make this uniform this is the password you're going to be using when you spin it up here is a volume Mount so basically this is telling Docker to grab some place in your dis and bind it to The Container so that it can actually persist data as you're working on this and you can dive more into this if you want to but really you can just like install this file now the second thing you need to do is install docker desktop if you're on Mac and there's other Solutions out there but basically you need some type of Docker Damon that can spin up these containers and images for you so I'm going to go ahead and just spin up Docker desktop when it is ready I can do a Docker compose up and you'll see that it's going to pull in the docker file it's going to spin it up and it's going to run my postgress service so right now it's saying the database system is ready to accept connections and I might just go over here and rename this I'll just go and say this this is like my my DB and uh I'll rename this one to like next all right so now we should hopefully never need to look at this Docker compos file other than what we're going to need to do is go over here and change the password which I believe is this line I'm going to say example and then this is just going to be Local Host instead of the z0 I think they'll both work the same way um and then for SL DB think we want to give it an actual name I think we want to call it postrest like that and hopefully this will work now what I would recommend doing is don't hard code this URL I would actually make a EnV file and I would paste in the full URL there okay so same thing it's just the username of your connection URL the password the location or the host you could call it the port and then your database name so I'm going to go ahead and grab this environment variable and instead of hardcoding it I'm going to say process. do database URL and then I'll just put it a exclamation mark so that typescript is happy about that and we should hopefully be good so again what we're doing is we're setting up drizzle orm and we're also pulling in post grass so that we can connect to a database and persist our data um but there is another step where we need to Define like a schema let's go here and say schema. TS and then we are going to just go ahead and start trying to define a table that we're going to need to use in our postgress database all right so just to kind of get us started I grab some code and this is how you define your schema you basically need to create a bunch of different variables in our case I'm making a table called testing that table consists of a column called ID which is a type of text ID not n primary key and then also a name column and we're just kind of creating this right now so we can verify like do we set this up all correctly and then this make sure whenever you import these things make sure you import them from drizzle orm PG core because again we're using postc so make sure you import it from the right package so now that we have a basic schema file set up we're going to go ahead and try to pass it in here so we need to say import Star from schema and then we're going to go ahead and try to pass in uh we probably as schema and we'll pass it in here like this and probably wrap it that should make it happy and now we have this DB object and so if we wanted to potentially read or write from the database we could do that but let me show you something else that's really important when it comes to drizzle there's something called drizzle kit which we already installed and this is a tool that's very useful for basically creating your migration scripts or just applying changes to your postgress database the way SQL databases work is you have to write code SQL statements to create tables update their columns rename columns Define the types on those columns Etc looks kind of like this and the cool thing about drizzle kit is it does all this for you you don't have to worry about like writing these migration scripts usually so to get started with Drizzle kit I'm going to go ahead and copy this code and then I'm going to make a file called drizzle config.sys drizzle config.sys we want to use the PG driver for postgress and then for connection string we just need to use that database URL that we defined and this is basically telling drizzle kit how to connect to your database when you want to run certain commands Okay so if this is set up correctly what we can do go to our package Json and we're going to add a new one called dbon push and we're going to paste in this command this is basically telling drizzle that Hey whenever someone makes to our scheme of files I need you to use this config file figure out how to connect to my database and apply those changes to that database so if hopefully if I did this right I can say mpm run DB push and that should apply the changes to my locally running uh postest table so you can see when I'm running this command it's saying hey do you want to run this command create table if it doesn't exist I'm going to say yes go ahead and execute that and it did work fine and so that leads us to the third thing that you're going to need if you're using drizzle that's drizzle Studio it's a nice UI that gives you a nice experience for modifying inserting records deleting records kind of like mycle workbench if you Ed that but not as feature Rich so let's scroll down and let's see how to do this basically you run MPX drizzle kit Studio I like making aliases and my package Json so let's just go ahead and say like DB studio and we're going to run that command here and so in a third terminal we could call this studio I can say mpm run DB studio um it is complaining that I don't have a PG package so let's just go ahead and install npm install PG I guess I missed doing that at some point and then we can go ahead and just run the studio and you'll get a link down here if you go ahead and command click that link it'll open up your Chrome tab to drizzle studio and again this is the UI that you can use to basically connect to your tables and look at the data if you notice here we have a table called testing so our previous command or DB push command look through our schema it figure out how to create this table and then it created for us so if we want to go ahead and add a record here I can just go and say like um ID we'll keep that empty right now say name is hello world I save this does this Auto add something I'll just go ahead and say like eight whatever so now we have one record in our table and this is kind of setting us up because we want to connect our nextjs application to this database to be able to fetch this data and from this table right at this point um I'm going to commit I do see that this EnV file is here so let's find the get ignore right here go down to the bottom and I'll sayb we do not want to commit our en files ever let's just do that and then we're going to go ahead and add all this so I'm just going to go ahead and click this plus sign I'll say setting up drizzle omm okay go ahead and commit that Sy that up and we should be good another thing that most projects do is they'll have a env. sample and this is so if someone were to clone the project they will know how to like get this go going locally right so I'm going to say replace this with the real URL of your postgress database and I'll probably just go ahead and add that to I'm adding. sample I would say usually the setup the initial setup of these tutorial projects is like the most boring part but if you haven't done it before it's good to have someone kind of walk you through the process cuz can be kind of overwhelming it's a lot of stuff you have to connect together and um hopefully you're learning something by watching me do this so now I want to verify can our nextjs application can it load that record when it loads right so nextjs is a server side rendering Library like primarily right and then you can opt in the client sign rendering and doing all this other stuff so if we were to kind of like delete all of this code I want to just keep this simple and kind of verify that we can actually red dat from the database I'll talk about how the app router like Works later on U when we get to it but let's just focus on how do we get some data back from that database I'm going to say const and I want to say like items is equal to DB we're going to go ahead and import that from that DB um remember that DB thing we created over here there's this index file and that's kind of hooking everything up with Drizzle to our database but we want going to go ahead and use that DB object and we're going to wait on it so make sure you put async here so that we can do like an actual asynchronous server call and then we'll say DB dot I think we can do query and then we can say dot testing and then we want to say find mini and just go ahead and run that and so the way nextjs works is when you navigate to this route it's going to run this code which is going to fetch data from our database and then we get our items back notice how this is type safe already it's a list of items but we can just go ahead and map over that let's just go and say early brace items. map for every item we want to just go ahead and return something make sure we put a key here of the ID and then over here we can just say item. name all right so moment of truth if we go back we should see Hello World pop up and it does because we're loading from the ACT ual database so congratulation you have everything set up you're connected to the database you're fetching some data down and if you able to see this that means that you have everything set up correctly if I were to change this to something else like what is up go ahead and save that go back to my UI and refresh it again just to kind of emphasize that we are connected to a postgress database that's running in that Docker compose setup and we're storing and retrieving data so now that we have the database set up let's move on to one of the core pieces of functionality or application will need and that is authentication how can you set authentication up with nextjs one of the easiest ways is by using something called next off so let's go to next oj. org and let's go ahead and check out the getting started guide I'm going to go ahead and just run this command copy that and then I'll open up a new terminal and I'll install that package so when it comes to next off they do have documentation but for some reason they still haven't like updated it to just use the new app router like they still have Pages stuff in here so read the fine print it's saying if you want to use route handlers follow this guide basically you follow this guide and it tells you to make an app API o directory um next o folder so let's just go ahead and make a new folder like that and I think I can just put it right here uh I think I made it a little bit a wrong app thing let's just delete that and then over here you make one called route. TS so I'll just go ahead and make a new file say route. TS s and we're going to copy in some of this code here like this and this is basically an endpoint that various thirdparty providers are going to use to send you tokens and make sure that you're logged in and registered and stuff like that but this next off takes in a configuration and so if you want to use this you basically need to pass it some custom things so the first thing we want to pass is an adapter this is basically telling next off how it can connect to our database using drizzle and then I believe we're going to have to install a drizzle adapter so let's just go and install at o/ drizzle adapter and then we should be able to Auto Import this in and then we also want to Auto Import our database object like this and that should hopefully work well but if you do want more information about this go to OJs dodev and you'll see that there's an official drizzle orm adapter for this this is how you can kind of get it set up um add the adapter to your pages API next off. TS file and this is kind of the code that we were about to do so let's just go a and copy the providers as well like this I do plan to use a Google provider in this example so we need to import the Google Provider from next o like that and to use this it actually requires a Google client ID and a client secret I'm just going to pretend like they're set for right now but we'll have to go and like I'll walk you through how to get that all set up with off now additionally what we're going to need to do is in our schema file we have to Define some new tables because next off is going to try to write to a user table it tries to write to an accounts table and you can see in this example setup you just go ahead and pull in all this code sessions verification tokens Etc and make sure you grab the postgress one so over here I'm on drizzle adapter they tell you how to set up with postgress let's go to schema and let's just paste in all that stuff okay and let's make sure I move the Imports to the top of the file like this and I'm sure I have duplicates so let's delete that now we are getting a little typescript error about this adapter and what people online are saying is you want to import the type adapter and just basically cast this as an adapter object two weeks ago people were saying that this is just like broken but that's coding for you right literally stuff is breaking all the time and you have to sit there and try to figure out how to fix it so now if this is set up correctly which I hope it is you have to set up a Google off provider so I'm going to walk you through how you do that so if you go into Google cloud and go to API and services you can make a new project here so I'm going to make one called uh we'll call it devinder go ahead and click create and this might take couple seconds to create um but once it's done you can go ahead and click over here and you can dive into this project and select it okay everything seems good and we want to first of all click on configure consent screen I do believe you have to do that first before you can create an API key so I'm going to say this is going to be an external app the app name will be Dev binder support email I'll just use my email account um all this other stuff I believe you might be able to just leave blank I don't think you need Local Host here but let's just say webdev Cody gmail.com save and continue just keep on saying save and continue and then fin like the bottom I'll say back the dashboard um you do want to click before you go to production like you want to click publish app we're not going to probably do that into this tutorial but what we need is credentials after you set up what we just did you need to go to credentials and you need to create a new credential here I'll say we want an oo client ID okay let's just go and say this is a web application called devinder and we want to add an authorized JavaScript origin so that' be HTTP Local Host 3000 and then for the redirect URLs we want to add that API that we've been kind of working on so remember it's API SLO and then you want to do um I think it's callbacks Google I don't remember off the top of my head I always have to go look this up it's either call back or call back Google um let's just save it and uh at this point you'll get back a client ID you can copy that and that is what this Google client ID is so let's go to here I'll say Google client ID is equal to this and then also we have a Google client secret that we need to set up which is here I'll copy that one paste it in and then again let's make sure we update our sample so that if anyone were to clone this project they can get the setup themselves now that we've set all that stuff up we have to do some more work right I think we need to provide a setup of a provider that wraps her nextjs application so that we know if we're authenticated or not so let's go back to the next off guide and notice here they have something called a session provider so I think I can just import this like that and we want to wrap our code uh with our session provider I believe yeah so let's just go ahead and say session provider and we're going to wrap steam toggle with this so we are running into an issue with the session provider it has to run into client component so in order to get this working you have to say make a new file called providers and then we are going to go ahead and grab kind of all this code and I'll say export function providers and we're going to go ahead and just return that code there we want to make sure we bring in children over here like that make sure we Auto Import some stuff make sure we bring the theme provider and then we want to go ahead and just render out the children put that there Auto Import that now the reason you're doing this is because you want to put use client at the top of this so that nextjs knows how to properly do the hydration and the server side rendering and client side rendering so let's just go ahead and say providers and then I'm going to wrap all this code that we had here I put that there and go ahead and delete that save it okay and now we can kind of delete this stuff and hopefully this will work now okay so it's loading everything should be okay so I think this would be a good opportunity to kind of abstract the header away let's just go ahead and make a new file called header. TSX we're going to say export function header go ahead and just return I'm a header component and put that code in there we do want the mode toggle and we're going to say use client here because we want to bring in some Dynamic functionality okay so in nextjs and inside of OJs you can check if someone's logged in by saying con session equals use session like that right so now that we have this session variable we can check if someone is logged in or not I can say if session. dat uh we could probably do like a turn are here and then I'm going to go ahead and just say make a button like this go ahead and import it and if we are logged then we're going to go ahe and just say sign out and if we're not logged in we will have another button that says sign in let's just say sign in like this save it and so on the button itself we have this ability to call a sign in function that's provided from next off and you can actually pass like Google to this if you want to if you just want it to automatically go to the Google sign in so we could try doing that um but but probably we should put the sign in on the real sign in button so let's paste it down here and over here I'll say sign out like that okay so now that we have the header go back to the layout and the reason we're doing this is so we have a nice header component we kind of abstracted away that logic and now we should see a header that says sign in all right so before we can actually click the signin button though remember we did all this like Prisma stuff where we added new tables I don't think we ever applied those so let's go to another terminal down here I'm going to say mpm run DB push and that's going to Loop over all of the tables that we just created such as the accounts table the sessions table the users table verification and have all this SQL kind of generated for us I'm going to say yes I want to apply those and now it says changes applied and hopefully now our next app might just restart it just for good measures let just go ah and click sign in and then I'm going to click my user account and now notice it says sign out at the top so now we are actually authenticated the UI knows that we're logged in and it actually knows who we're logged in as if I were to go and print out um in the header or in the body or something I'll just go ahead and print out like session. dat. user.name and you should see my name pop up okay so we know we are logged in as uh my account awesome so again all this all this was just set up we're still just setting up our nextjs application to be off ready to also have a nice UI kit using Shad CN to have a database with post grass and drizzle orm and we're kind of I think done hopefully cross my fingers done setting up and gluing all this stuff together and we actually have authentication with Google working which is a big win so I'm going to go over here I'm going go ahead and commit this and I will say finish setting up next off go ahead and sync that up and we should be good so if you're watching this tutorial for the first time you're like wow we just spent like 30 minutes just setting up an application this is why I recommend finding a template just start with a template everything is already hooked together you have off you have your database you have some initial landing page a header a footer already set up for you with nextjs I think that's like the easiest way to get started but going through all these steps I think helps people understand how to set up an application for yourself so let's actually start trying to implement some of this functionality so the first thing that I would want to do for this devinder application is for allowing someone to basically upload a session and what I mean by a session um like a Dev session is I want to have some initial information about maybe what project they're working on what type of code they're writing is it rust is it go is it JavaScript typescript and so they can basically create their session and other people can browse the sessions and they maybe click on their sessions so they can view what they're doing and then they can actually start live coding together or just like join a live chat or a video call where you can view their screen and see what they're doing I think that's the first step so creating this session would be kind of the first step and we'll do like iterative development here and just slowly add this in so schema first thing we want to do is I'm going to make another table and now we already have one called session so it can kind of get a little bit confusing so instead let's just call it a room okay this is like a Dev room I'll just call it a room and what we want to do here is we do want to have this room reference a user so as a user if I create a new room I want that room to belong to me so that when I decide I wanted to delete that room or close the room or something I'm the one with the permissions okay so we definitely want a user ID here and the way this syntax works is we say hey we want this user ID to be a type text and then we want this to reference the user table which was defined up here remember we have a users table and this is how you can kind of do references with Drizzle is just like that and I know there's a lot of stuff I kind of copied in and didn't really talk about but I would say just focus on the new things we're adding and then go back and try to understand the things that we just previously added for next off and the second options for references is basically saying hey if the user were to delete his account make sure you also delete this room from his account too so definitely want a user ID there we also probably want a name of the room let's just go and do that maybe I'll say like language that could be a text maybe they want to type in typescript or JavaScript or we could have like a drop down that allows them to choose what's their primary language of the project um maybe a GitHub link or repo maybe you want to be able to add in a link to a GitHub repo maybe you don't I think that's a good enough start that's a lot of stuff so again whenever you create a new table or something remember mpm run DB push and make sure you apply those changes like that and now our table will have access for us to store a room and Associate that with the user all right so let's make a new route we haven't talked about nextjs routes yet but in this app folder any directory you add in basically is used for the routing so if I were to make a new one called Rooms or if I want to call it like create room this would allow us to basically go here and say SLC create room and that's going to look for a page. TSX file so if I were to go here and say page TSX and say export default function create room page go ahead and just return maybe uh a div maybe we want like a title that says create room and that should be good for right now so let's test that out if I go to create room it says create room up here okay so the initial thing is probably getting a form where a user can type in like the information about the room the description the language they're using and then have a submit button so that'll persist some data to a database let's just go ahead and add a form in here and I'm going to go ahead and add in some inputs now I will since we're using Shad CN they do recommend um at least the approach they do is they use um react hook form which I think it's just a better developer experience than doing like HTML form inputs and stuff like that so I'm going to do it the Shad CN way so if I go over here you should be able to find a form and we have to install a couple of things that kind of get this going right so the first thing that we need to do is we need to install the form component so let's go ahead and add the form component down here and then secondly we are going to make a new file we're going to call this the create room form. TSX because I want this to be a client component okay so export function create room form and then we're going to go ahead and just start pasting in some things so the first thing you need to paste in is Zod this is the way we're going to validate our form if you need more more fine-tune validation you definitely want to bring in Zod so I'm going to go ahead and install that and make sure it's set up and then you define a form schema we're going to keep it as username for now just to make sure this all works then we'll come back and we'll change it so the next step is we need to bring in the Zod resolver and the use form hook so let's just go ahead and do that and I think when we added the form with shad SC and it already installed those things so we should be good let's just continue down so Step One is they Define a form grab this go ahead and put it in that component there and this is basically saying hey just make a form data structure that allows us to call different methods on it so at this point we could say like form dot I don't know clear errors reset this is an important object you're going to need to use um basically to control the form and like keep track of values and stuff all right so the next step Define an onsubmit Handler let's just go ahead and copy that paste it in and this is going to be typed uh correctly so whatever values you define up here in your form schema notice how you have those values right here you don't have to mess with like form data and pull those data out of the form object that all works and now they tell you to build your form so let's just go ahead and pull in those components right here now we are missing input so I do want to add the input component which we can say add input that should be installed then we should be able to see it soon let's keep scrolling a little bit and here's the example of their form so I can go ahead and copy this whole thing and we're going to scroll down and we're going to return that entire form like this awesome so I know it's a lot of copying pasting but that's literally what you end up doing in coding right once you understand like what the codes doing you start just copying and pasting these patterns all throughout your code base let's make sure this works I'm going to go to our form page and I'm going to bring in the create room form that we just toin and I'm going to save this file and we should be able to go back to our app and we see a form here now the cool thing is this has validation built in already um it's a little bit hard to see I'm not sure why the the dark red is so dark um but we can probably correct that later so now this requires you to type in at least two characters and then the validation goes away okay this is one reason why I wanted to just bring in the way Shad Cen uses a form because if you wanted to implement this all yourself it's a lot of extra logic it's a lot of keeping track of like validation errors so again I think this is the best user experience um and developer experience out of the box um which is why I recommend it all right so let's keep pushing forward what do we need from the user when they want to create a room right the first thing they want a name you definitely want to name the room and I'll change that to a Min of one and then they also o want a description which I might actually make that required after all I can go back to the schema and change that but we're going to go ahead and just default it to an empty string there and this will be called name actually we're going to grab this whole form field and we're going to do another one for description so here we'll say description we'll say description um this is uh please describe your room please please describe what you'll be coding on technically I don't really like placeholders I'll be honest with you if you have a label what's the point of a placeholder I'm going to get rid of placeholders and now we should see a name and we also see a description and then I'll say this is your public room name okay now what other things do we need so let's look at the schema we have a language and then we also have a git repo okay so we could make some form fields for those so I'll say go up here we're going to add one for GitHub repo which I'll make it required and then I'll also say language that could be required um I am using co-pilot just to kind of do some of this nitty-gritty stuff which I don't want to do by hand anymore and then we're going to go ahead and say this will be GitHub repo GitHub repo please put a link to the project you are working on okay and then finally we want the language um language programming language I might even say primary so it makes more sense the primary programming language you are working with that's basically so you can find people who are working with typescript like you don't want to go and join a a rust room if you have no idea what you know how Russ works or you don't want to join a PHP room if you're mainly a developer okay so now we have all these fields and we should be able to create the room is there anything else that we're missing from the schema looks like we have everything and so at this point there are some stylistic things we can do on this page like if you wanted to wrap this whole thing in a div we do that and we do want to give this a class name I'm going to say container MX Auto just so it's not like hugging the left side of the page because that was kind of not the best right we want a little bit of padding and then the create room um actually now I think about it we shouldn't put that here that should live on the page let's go back to the page and I'm going to just do that and we want to keep the form here I apologize for that do this all right um a little bit more styling I could go ahead and just say this is a class name this is text for EXL fond bulb if you want to there you go you wanted to put some gap between these two things you could say display Flex column gap of four that's one way you can do it maybe even gap of eight okay and then for the title itself you could say uh this is going to be like a padding top of 12 so push it down a little bit okay so now we have a nicer looking form and then also the bottom of this I'm going to say adding bottom of 24 that when I scroll down you can actually see the button okay looks nicer right now technically for description we could use like a text area but I think input's fine so let's make sure this All Passes validation everything should be required okay not sure why I typed in GitHub repo and it did throw this weird uncontrolled issue maybe we should look into that GitHub GitHub repo is a field language is a field yeah I don't I don't know why that thing uh threw a warning there it kind of concerns me let me do a hard refresh and try it again okay it's gone now that's kind of weird okay so at this point when someone submits this form we want to track all of the values that they filled in and send that over to the back end so how can we do that we are going to basically find that on submit function here and instead of console logging the values we want to basically to do um invoke a server action to store the data in our database okay so the cool thing about nextjs um which I kind of like is the fact that you can create something called server actions and those are functions that you can just invoke directly in your front end client code and that's going to run some backend code so I like to make like an actions file here so I could say actions. TS I don't think I need TSX there I'm just say actions. TS and then at the top I'll say use server and then and we are going to export a function I think it needs to be async so export async function and we'll call it create room action I like adding the action suffix to my actions just so it's a little bit more clear um but what this action needs to do is take in the data so this could basically take in some room information um which again would have to be some of that data that we just talked about and I think what we could do I'm going to go over to our schema I'm going to say export type room Capital like this I'll say room dot um I'll say type of room. infer select I believe and so this is a way that basically allows you to in your front end code you can type some of the stuff that's get passed in I'm going to import that you hover over it notice it has user ID name description language and GitHub repo so that helps us not have to redefine types everywhere and in fact I can use um an Emit and I could just emit the ID I think it was a user ID um because when you first create a room the user is going to send over the data but you don't know what their user ID is and you don't want to trust what user ID they sent over so the way that you can create records and I believe you can say await DB dot make sure you import that and let's look over here I think you need to do insert and then you need to pass in the table like this and then we're going to say values and then we're going to pass in that room um we have to rename this a little bit they'll call that room data and I this is complaining because I think it thinks that a user ID is required so we will have to kind of figure out how to pass in a user ID okay and that should insert into the databases everything works fine we could test this out and come back and fix it up later um because there is a little bit more we're going to have to do to figure out if we're authenticated when someone calls this server action okay so on the front end side of things we should be able to just invoke This Server action directly so I can just go ahead and say create room action and I'll import it directly into our client component and what we need to do is pass in values which should have the same exact type signature and it should match that room that we created and uh if everything worked fine um if you're a fan of doing like a weights and asyn a weights you could just go ahead and like do that and then we can say let's redirect to the homepage so how do you redirect well in the top of this file here the top of the form I'll say const router is equal to use router import that from next navigation and then I'm going to say router. push we want to go to the homepage so this will create the form it'll wait for the room to uh be created when that's persist is the database we redirect the user back to the homepage and there's more stuff you can do for like optimistic updates and like loaders and Spinners we'll probably come back and try to do that in a little bit but let's just focus on the key thing of like how do we get this data inserted so let's go back to our app and let's just test it out I'm going to go ahead and save my room as uh working on devinder and then I'm going to go ahead and say description is a cool application where you can and pair program with random people online GitHub repo I don't have one so let's just go a and type some random stuff in and then I'll say typescript for the primary language so let's test this out moment of truth if I click submit um must contain at most 50 characters okay let's let's change that I'll do 250 and click submit there we go all right so this one aired out it's saying insert or update on table room violates foreign key constraint room user ID user ID FK so the issue is is that we actually need to pass in a real user ID remember that to-do that we added in we have to actually do this correctly and so the way that you can validate the session and make sure that the user who's making the request is actually logged in we could go back to I think um I'm going to go back over here and I'm going to make a new file inside this called o. TS and we're going to go ahead and say export function get server session and then we can just go ahead and call a method I'm going to rename this to get session and then we're going to go ahead and import get server session so this is a method from next off you can use to basically get the server session now the second thing we have to pass this is going to be your off config now we made the Au config over here this is the off config so technically I should probably pull this out and I'm going to just put it here I'm going to say export con off config is equal to this we might have to reort some stuff and rearrange some stuff so we'll do that and uh make sure you import DB import that import that we're going to go back to the route and we actually want to import the oth config from a centralized place so that we don't have this like duplicated everywhere and then also in O we're going to pass an O config here so that when they call get session from our action it knows how to connect to post grass using drizzle okay so now going back to the action let's just go and say concession is equal to get await get session and I'll import that okay and we should get back a session if it's defined hopefully and if not we should get back null so let's save this go back I'm going to go ahead and just click submit here and notice that it did print out the object so we know we're logged in um because that's defined so using the session remember we need to get the user ID so let's just go and say session. user dot oh wait there's no user ID so we have to kind of do some additional configuration in next doth so that we know what the user ID is of the user making the request now to be honest I don't remember this off the top of my head I have messed with Drizzle in next off before I'm going to copy some code over and I'll kind of explain it to you over here I'm going to paste in this session strategy JWT there's basically two ways you can use authentication there's session or there's JWT JWT is necessary if you want to use middleware which we might end up using on this project so I'm going to go ahead and just bring that in and then we're going to bring over these call back so callbacks allow you to Define custom Logic for when a user tries to sign in or register and so you can kind of get and look up the user based on their email here and so what this code is doing is like when you try to log in for the first time it's going to take your token and it's going to try to find a user who's matching your token's email okay and then I mean obviously there's no user we throw an error and then we return this object that has the same information that the session had before but now we also have a user ID which is what we were missing in our action okay so this is how you can do this second thing that this thing is not typed correctly so let's just go ahead and give this a satisfies as uh yeah the entire o config we want to make sure that it satisfies o options so that it knows what token and user is okay um so for session. user what I'm actually going to do is I'm just going to say let this equal to I'm going to do this the ID of this we'll say name email and image okay so that should hopefully just overwrite the user object and just let it have all the stuff um it's complaining about ID and that's because we need to overload the default type of next off so I'm going to go ahead and copy this as well go ahead and Auto Import some stuff and uh there you have it all right so now going back to our actions file um what we want to do is we want to say if there is no session we're going to throw a new error you must be logged in to create this [Music] room like this and then other otherwise you can just kind of run the logic so here we should have session. user. ID notice that ID is now defined that's the whole reason why we like went to the other file and had to configure everything else again so let's see if this will at least throw an error or give us a uh insert a record for us let's go back I'm going to go ahead and just um sign in again because it cleared out my user after changing all that stuff go ahead and sign in and I'm not going to type a full description here I'm just going go ahead and type in some stuff click submit and what happened you must be logged in to create this room so I think to use a jbt style um strategy I mean we do have to import a next o secret thing so this is what it's going to use to sign the JWT if you don't understand how this works it's should be fine um so we are going to add that to the sample as well make this something secret all right so let's let's try it again let's go back to the app click submit um we are going to try oh we have to sign back in let's sign in here do this make sure we're signed in can we just type in some random stuff and I click submit and it did redirect us back to the homepage go ahead and just refresh and see if the data shows up all right so going back to drizzle Studio which by the way whenever you like run a migration script sometimes you do have to start drizzle studio um so if you restart it you can refresh it and you'll see that we have account room session testing user all this stuff is showing up and if we look at room notice that it's showing up now so we're going to go full circle we're going to go back to our main page here and what we want to do is instead of querying this testing table we're going to query room and we're going to get back all the rooms we'll say rooms we'll say room and then we want definitely the room ID which um we should probably add an auto incrementing room ID to this so we'll probably have to fix that but we can at least do something like this which means that we can go back to our UI and refresh and notice that our room information does show up for us which is nice so let us fix that I think I need to go to the schema now instead of using an auto incrementing column I might actually just grab this I think this will generate a uid for us automatically and we could just put this here I could say ID is this and then we we'll import uid all this ID we'll say Generate random uid and then this will be not null primary key I think this is how you might be able to do it um I'm going to go to gzel Studio I do want to delete this one uh I can't even delete this so what I'm going to do is just try to run DB push like that and yep add that in refresh this page there you have it now we have a unique ID for that record and we can kind of use that um over here on the page so instead of doing room name we'll say ID I think we made a lot of code changes we're going to go back and just make sure that we're not missing anything we have a error here IDE is missing I think what we want to do is emit um ID as well that's how you do it and then this will automatically give us an ID when the room is created and that should be good so let's go ahead and I think we should commit we did a lot of code changes a lot of stuff going on and um yeah hopefully you guys aren't lost because honestly I was getting lost at some points as well I'll go ah and add all this and then we will say switch ing to D strategy I'm adding ID to the session and creating the room when submitting the form go ahead and submit that so now at this part what I would like to do is probably just start making this application look a little nicer so let's start with the header let's style it out a little bit and let's pretend like we have like a logo for this application um also the metadata up here create next app we should probably update that let's go to our layout I believe we have some metadata that's defined here and we are going to just go ahead and change this to be Dev finder that could be in the title and then the description will be an application to help pair program with random devs online Okay so let's make sure that updates devinder does pop up that's good second thing let's work on the header so let's go and find our header component all right right and again like I use command P fuzzy search is your best friend when it comes to coding command P type in the component name and press enter in case um you guys were just confused how fast I just load up that file very very good to learn that shortcut so in the header itself on the left we want a logo probably and on the right we want all this sign in and sign out button stuff so for positioning the logo and then like these actions what we can do is get this a flex and we can say just a ify between and what we also need to do is I'm actually going to cut this out and I'm going to put this on a div right so we're going to have the header as a top level element and then on the div itself we're actually going to move some of this stuff in here and then for logo I'm just going to wrap another div and so what justify between does is like it's going to put spacing between these two divs you'll see ones at the far left now and then we also have the stuff in the far right let's go ahead and right here I'll say class name we want to do a container right the issue with what we have right now if you zoom out really far notice that like I know you can probably not even see it but if you're on a 4k monitor like this layout is just keeps on expanding it's not the best user experience so typically you want to put a container and an MX Auto on like the outer header so that even if you keep zooming out this thing will stay inside a container of the page um because with a very very large monitor is just it looks terrible second thing we should probably do is we could change the header color a little bit so if we're in dark mode I will say dark and we'll say BG we could probably say like gray of 900 let's kind of test that out okay we got a little bit of different color here just to kind of differentiate that and then you'll see the vertical alignment for the logo we want to make sure everything in here is vertically aligned so we can say item Center on that div and that'll vertically align it and then also we can either add a fixed height to the header or we could just add some padding inside of it um so maybe even padding y of 12 that was way too much um let's do padding y have two maybe okay so now I have a decent looking header maybe even more padding than that like a four there we go all right so now if you go to light mode we probably want to also make sure that we change the styling to be BG gray 50 okay again in Tailwind if you prefix it with dark then that's going to only apply to dark mode otherwise this is like the default so now if you look at this it's kind of 100 would be a little bit better there you go now if I go back to dark and light mode we can kind of style those independently as needed some additional things we should probably do is um instead of the sign out button being this jarring it's like it's pretty taking up all the real estate right we could instead have this be an account drop down so again we need a drop down so I'm going to go ahead and grab this code and inside the header itself one thing you can do is I'll just say function count drop down and then I'm going to return all this and I'm going to copy this and just paste it in the top now I will say like when I do tutorials I try to walk you through like okay how do you use Tailwind style some of this stuff how do you use Shad scen to bring in these different components but as you get more familiar with this I would recommend just signing up for like a Tailwind component system that has has like your header already styled you don't have to waste a bunch of time like doing this tedious stuff that's just me maybe you really enjoy like custom styling all this stuff but uh I would rather just have a header that I can just copy and paste and be ready to work on so here is the drop down and so what I want to do is I want to wrap uh my name inside the drop down itself so uh we have the account drop down what we could do is I'm going to paste this over here and then we will take this and we're going to move it into the drop down itself okay so instead of it saying open here I'll put my name and we don't have session so we can go ahead and cut that out and put it right there like this um we still want session so I'm just going to go ahead and also import it here and the reason I'm importing in two different places is that this makes this a nice like it makes refactoring easy I can cut this into another file and everything will work perfectly fine if you want to just prop drill it in you could do that and like this could take in session or something but I think it's fine just you know that's why we have hooks hooks make it very nice and composable to just bring in reusable code so now if you click on this it shows the drop down and so what I'm trying to do is I want to move the sign out button into an option here okay so let's just go ahead and move this whole button and then we're going to put it over here and then if the data is defined on the session um I could also say is logged in that might make it a little bit easier I'll double negate that or cast it to a Boolean and if you're if and then so I'm going to say is logged in then we're going to have the sign out button now instead of doing a button here we actually want a drop down menu item so let's just go ahead and paste in the drop down menu item it'll say sign out we're going to take this onclick method and we'll put it right there we'll do the same thing for sign in and we'll make sure we take the right code here that sign in and uh yeah it should be good delete these other options and we don't need this my account thing I'll just go ahe and delete that in the separator all right so now you hover over it it says sign out but it'll be nice if there's an icon here so let's go to lucid dodev and let's try to find like a sign out okay there's it's called log out so let's do here we'll say log out icon like this and then over here we'll say log in icon okay let's check this out click it it says sign out pretty cool we should probably add a couple of styling so I'm going to add some here you could just add some margin right of two to this log out icon like this and then uh actually do this as well all right so now it says sign out pretty cool um I will say that I want to put a little bit of space in between these things and also it doesn't seem very vertically aligned then we can also change this whole thing to like have a button style cuz right now it doesn't seem like it's clickable so on the drop down trigger over here I think you can say as child and we're going to add a button like this we're going to go ahead and paste this in and hopefully a button will show up now it says my name and then what I can also do is we'll give this a variant of outline there we go now you can play around with it maybe there's something else we should use like maybe you should use a link okay I think that's a little bit better what we could also do inside the button we need to display the image of the user let's go ahead and bring in next image okay like this and we're going to go ahead and import source and that should be able to be pointing to session data user and I think we have like an an image okay we'll do this and then we could just hard code some width of like 50 and see how it looks do 50 we'll say height of 50 and then uh alt ult will be uh your avatar now I think about it chaden actually has an avatar component so I think it'd be better if we go back to Shaden we find Avatar okay looks like this we can go ahead and just import this Avatar otherwise you're going to have to do some like styling and rounding of the image and stuff like that so if we have a component that already does that for us let's just go and import it okay I'm going to paste that Avatar in right there and then we going to figure out how to use it you use it like this so let's just go ahead and copy that whole thing in and paste it in and then for Source we're going to go ahead and just paste this and a lot of the stuff we can go away now like we didn't need to do all that I apologize for even doing that in the first place the issue is that the image could potentially be undefined so I'm going to make it fall back on an empty string and if it's not defined you have this fallback thing here right and so technically you could put like the initials of the user we we know the name is right here right you could put the initials here but let's see if does this work let's go to our app and here you go secondly let's put a little bit of Gap in between the image and my name different ways you can do that I mean you could just do some margin uh like this sometimes I like just using a flex and a gap or Space X and then for this uh notice how this is not like vertically aligned it's kind of weird looking so what we want to do is we want to find where that mode toggle is and here we probably want to say Flex item Center Gap four okay there we go looks a little bit better again I'm just trying to teach you all how to do this I would try to find like a pre-made component you don't have to waste your time doing all this um all right so now we got Dev finder it would be cool if we had like a nice icon up here I'm going to go to my own icon generate ai.com application that I worked on this is another site that I kind of uh worked on a while back and I want to make a magnifying glass with a computer okay we'll just go ahead and use I don't know cyan we'll do Dolly 3 because it just it's going to look much better and what should we do for the stop let's just do pop art and let's generate an icon and see if it looks pretty good yeah I mean it looks pretty fun to me so let's just go ahead and download this we'll just call it icon we're going to click on this and we're going to go to Quick actions I will say convert the image CU we do want it to be a PNG and we want it to be a little bit smaller because right now it's huge like 2 megabytes or something like that and then we're going to go over here we're going to say quick actions remove background and then I should be able to copy this and we're going to go to our Dev finder project we're going to go to public and we'll paste that in so now we should be able to access that icon up here and we are going to go ahead and say image and now we can actually use react image or sorry next image I'm going to say source and then I believe you can say public SL icon.png same thing with the width we could do I don't know 80 he could be 80 alt could be the application icon of a magnifying glass here we go um actually I don't think we need public there I think I can just say I icon and there we go popped up now obviously we want this to be on the same line so Flex gap of two item Center there we go and then it's also pretty big so let's just go ahead and reduce this to like 60 and the text itself I'm going to say text of extra large this is how you can kind of change your text size in Tailwind there you go so second thing you should do is when you have a header the top left logo and the name should always be clickable so we can wrap this entire thing in a link so if I go over here say this is a link and then I'm going to wrap this okay so this is how you can use nextjs links and we're going to go ahead and say href is equal to the homepage so if I was if I were to be on any other page and I click this it'll take us back to the homepage now I did mess up the styling there I think maybe uh I could just move this whole class thing to the link okay and then we can delete the div I don't think the div is needed and then also some hover state so if we hover over this thing maybe we should change the styling of it so I'm going to say hover that is a Tailwind uh directive I guess you could say which is going to or I guess it's called a pseudo selector and if you hover over this thing I'm going to go ahead and just make the text Ray of 100 let's just see how this works or we can make it a color let's just say blue of 800 that's a little too dark probably fail contrast again remember whenever you do stuff like this switch it over to light mode make sure that it still looks good notice that this is not even legible anymore these are some of the things you have to keep in mind which is why probably just doing an underline might be a little bit better so instead I'm going to say hover I'll say text uh underline actually I think you can say underline and uh there you go I do think there's a little bit too much padding on this thing I'm going to make it padding y of two again just reduce that and secondly if someone wants to upload create a room um you could potentially put a link in the header for that or we could just start working on this homepage uh for right now I'm not going to do a landing page maybe we'll do it later but I just want to try to query the data back from the back end remember we have like that page that has the form that creates the room now we need to basically allow the user to get back to that page so we could add a button up here or something to navigate to that create form page so that's what I'm going to do I think the header is good enough like I'm not going to waste too much time making this header perfect but how do we let's go to the page here how do we actually allow a user to navigate to that create room form page here um so let's just start with a button just add a button here I'm going to go ahead and say create room and then I'm going to import this button okay awesome create room it shows up and then I'm going to put that on the far right I'm just going to make it live over here and then also over here I want to put a title so let's just go ahead and add an H1 here and I'll say find Dev rooms save that it shows up awesome prob I want to make this be like a text for Excel and we want to wrap this whole thing in a div like this and I'm going to say give a class name of FX justify between item center now the justify between didn't work sometimes you have to go and inspect figure out why this thing did not expand to the full width now I've seen issues where I think this is like a flex column and since we're using a flex column here technically I think you have to say like w full um technically we don't even need Flex column here so let's just get rid of flex column and then we can get rid of the WF and then something is making them go all Center but we don't want that and then additionally justify between probably needs to go away too honestly I don't know why you have Flex there either let's just get rid of flex um this looks pretty good padding a little bit High I think I might even do like a 16 that might look a little bit better so again what we're doing is if you click on this create room button it should take you to that page so how do you redirect to a page well I think think you could just add a link here like this and I'm going to go ahead and wrap create room that they as child on the button and then this is going to take us to create room this as child thing is very important to understand when using Shad C and basically it says Hey create this as like the parent Dom node but then apply all the styles of what a button would be onto this so now like if you were to look at the Dom there's really just a link on the page right but it has all the styles of your button so it kind of like passes all the Styles down to whatever is nested inside of that first child so if you click on it should take you to the crate room page very awesome now one thing that you might have noticed is when I clicked on create room it took like a second for nextjs to navigate us to that new page honestly I don't know why it's so slow sometimes but I would say it'd be a better user experience if we had like a loader bar pop up so let me show you a really cool package that I like to use on my side project and that is nextjs top loader so let's just go ahead and install this bad boy over here go ahead and install that it's very easy to get set up you basically just import it into your layout so you know copy and paste coding that's all we do these days and then we're going to add next top loader we're going to put it right here above the header honestly it doesn't really matter where you put it I think you could technically put it like above the body if you wanted to okay so now we're getting our first weird bug with Drizzle and post grass so when you're dealing with a mySQL database there's usually a limit of how many open connections you can have but in nextjs every time you save a file it kind of like restarts your server and it reopens a brand new connection and so we're like using up all of the connections and we get this weird error where we could fix it by basically killing our nextjs server and restarting it but a better approach I think is you Google the error and this is a Dev only issue due to hot module reloading so he's saying you could basically do something like this inside of that database file where you only want to you kind of like cash the the DB object kind of sucks that you have to do this honestly so let's just see if we can kind of pull this in and figure out uh what to do with this so let's go to the DB file let's go to index and we're going to paste that all in some of the stuff we don't need like we don't need that we don't need that we could probably pull this to the top um let's declare the global here and let's keep looking so they make a let here definitely want that we'll put it up there and then if node EnV is production we don't want to do this stuff process just like keep doing this okay same thing here go ahead and paste that in don't think we need this anymore I think we want to take this and we want to pass it as a an argument to here probably delete that this I definitely like doing Curly braces all the time so I'm going to add those curly braces in and we're getting like a little typescript error so I think what's happening is that this needs to be um type of EMA and then also here process. EnV node this is something that you'll run into also with other ORS like this isn't just a drizzle issue this is a Next Issue where you have an or that's connecting and recre recreating database connections every time you refresh the page I've seen this issue happen with uh Prisma as well so just keep that in mind typically you have to do that St type of stuff um let's go back to our app and let's see if it uh works now yeah it's definitely super broken so I do need to just like stop my next app and just restart it but now we should never run into the issue again and that's real life coding for you you think you did everything good and then you run into weird issues you got to go Google find Solutions and we're good so again what were we doing we were adding a nextjs top loader the reason is because if you click on this link you're going to see a nice loader pop up here that just lets the user know that like hey your app is still loading just be patient you also see a loader up here in the top right so I think it just adds a nice little like feedback to users and it just makes your app look a little bit more professional so the next steps is we want to display all of the rooms that people have created so when this page loads we actually already get the rooms right right here we map over all the rooms it just looks pretty bad it just says ASDF and I had no idea what that was so what we could do instead is let's go to Shaden and there's a card component I like using cards um they're just nice to kind of display information so let's go ahead and install the card I don't think we have a card yet so let's load up a new tab here let's go to the bottom I'll install the card that's done and now we can go ahead and make a new component so let's just go up here I'll say function and we will call it the room card go ahead and return that information there and then I'm going to go ahead and copy this and paste it up here now I do want to kind of give you a little tip and trick I like to just put components and functions inside the same file until either a the file just becomes super long or B I find it more beneficial to move it out to a separate shared component I don't like just putting all my components inside this components folder unless they are used in more than one place if something is not used in more than one place I would highly recommend just keep it as close as possible to like the page that's using it or the header that's using it Etc anyway we have a room card here and what we want to do is we want want to display the room card instead of divs so I should be able to save this um instead of passing children though we're going to have to pass something else what we need to pass in is probably the name of the room I'm going to go ahead and just put some props here I'll say this would be like the room um actually technically we could just get the room type so I'm going to say room is a and I forgot how to get that schema so if we go to schema we do have type of room here so let's just go ahead and bring in that room autoimport that and now we should have access to room dot name and then down here we'll say room is equal to just pass in that room object so now the room card has access to like whatever it needs on that room data structure and it just makes our life a little bit easier so let's go back to our UI and this is what a card looks like also we can switch back to light mode make sure it looks good okay now I would probably say let's put some padding or margin underneath the fine rooms row so let's go back to here this whole section here we just want to say like margin bottom of 12 push it down a little bit even even maybe eight Whit space is like super important you need to understand like the concepts of white space how much space should you put behind or between like relative things anyway this is but I won't get into designing I'm not really a design expert we also have a description destion we could display so let's go back to our card and we'll say room dot description there you go and I really wish I named these better than AS ASDF but it's fine now for the content what we could put here is maybe like the GitHub URL so I'm just going to go ahead and put like a link say link and then we will just go ahead and say GitHub project we'll href this to room. href I'm sorry it's called the GitHub repo this is potentially nullable right so we don't want to display this unless it's defined I'm just going to go ahead and say like if this thing is defined we'll display the link and then we can also add in a GitHub icon which for some reason that's deprecated I don't know why they deprecated that from their project I have to go and read the documentation of that anyway on the link let's just go a and give this a class of flex item Center gap of two that cool now if you click this it'll take you to the page but we don't want to like have it change our current URL we wanted to load up a new tab so how do you do that well on the link itself you can say think it's Target and you can say blank and then you also need like this no referral thing or else you'll get like some security issues now if I click this it'll load up a new tab to your project if you have a project set up which we don't and then for the footer we could probably just put a button here so let's go down the footer instead of a paragraph tag we will say button and we will say join room there you go and then uh this could also be a link so we'll say as child we'll say this is a link this the link needs to go to a rooms slash in our case we're going to pretend like we have a route we haven't created this route yet but that's probably the next logical step of what we need to do and we're going to interpolate a string here and we'll say room dot uh ID so now if you click on this it'll redirect us to that room and then you can actually start setting up your live camera and talking to someone else who might be sharing their screen which should be pretty cool to uh get going so also if we were to create multiple rooms here let's create one more I'll say um working on devinder an application to help developers pair program with random developers online I'm trying to record a video for this okay so nice suscription GitHub link let's actually find one let's just go ahead and put the devinder link here and then primary language I'll say typescript just go and submit this so notice after we create the room it's not showing up on our landing page homepage and this is because nextjs when you deal with server actions you need to make sure that you tell nextjs to clear out the cache so that when a user were to hit your homepage again they can see all of the rooms that you've created right so let's go back to that modal remember we made an actions. TS file so what we want to do in this action TS file is after you've inserted this into your database you can call something called revalidate ath and then you basically can put whatever URL that you want to tell nextjs to like you need to just clear the cach so that next time someone hits that page they will get a fresh copy of everything there's also another way you can do it basically you could like have the UI do a force refresh and that'll kind of clear out your cache as well but this is kind of the way that they recommend it second thing I think we're going to run into when you deploy this to production is if I were to go to where's my page let's go to page here when this page loads right now this is a statically built page so if I were to actually go here and say mpm run build you'll see something very interesting it's going to treat this as a static page which means when you play the production it's never going to update it's always going to show like a hardcoded list of rooms not what you want right that's definitely not what we want and what we're going to do instead is we're going to mark this entire page as Dynamic right here if you see if it's a circle it is going to be a static page and we want this to have a Lambda symbol so a couple of ways we can do this now the first thing I'd recommend doing um is inside of the source directory honestly I would just put like a I don't know you can call it repository you can I can call it data I like to call it data access um some people call it services but I'll say data access and I'm going to make a file to abstract away this okay I'm going to go ahead and just say rooms. TS and then we're going to go ahead and just say export function get rooms that's going to call that method it's going to return rooms and then I'm going to just go ahead and say export async we want to import the datab base so let's go ahead and just make sure we have that imported like this but why we did this is because first of all it's good to abstract away your front end from like where your data is coming from so I'm going to go ahead and call get rooms like this and now our front and code doesn't know that we even are using Grizzle it doesn't know that we have a table called Rooms it just knows that it needs to call a method and one layer of abstraction is actually really good to do so keep get into the habit of doing something like this let's go to get rooms and again we're still going to have the issue with the caching so how do you work around the caching you say no store now this is an unstable method whatever unstable means but this is the way that nextjs docs actually recommend that you mark a function as Dynamic so that if any of your components or the component tree depends on that it'll Mark the entire route as dynamic as well okay so I'm going to rerun mpm run build just so that you're kind of aware of that caveat because this will totally make you waste a bunch of time unless you understand it and now notice that this is now considered a dynamic page and we won't have issues when we go live with our app I probably have to restart my next server because when you do an mpm run build with next it'll just mess up your next server um because they both share the same like build directory all right let's go ahead and refresh this now it should look good and let's try it one more time because we want to make sure that little bug doesn't actually happen so I'm going to go to create room in this case I am just going to go ahead and just like do a bunch of this stuff I'll click submit and notice that it does show up so now that we have three rooms here it would be nice if we styled these to be side by side in like columns so pretty easy to do basically we can make this whole thing be a grid wrap this whole thing in a grid and we'll say grid calls of three okay now we have cards that are side by side and what we could do is we could also say gap of four okay space them out a little bit just makes it look a little bit better go ahead and check out dark mode should be good now honestly I don't like how these join room buttons are like offset it probably be good to add some type of like fixed height to either here or add some like Flex I'm not going to get into that though because I do want to like focus more on the functionality not the styling so I think we made some good progress there are some things I'd probably nitpick about this UI but I'm not going to focus too hard in that what we want to do is we want to start working on the ability for someone to join rooms and share their webc cam or share their screen and have other people join those as well so you can have people collaborate with random strangers online and develop on the same project but let's commit what we have so far before we kind of get down that rabbit hole going to go ahead and commit everything and I'll say working on displaying all of the rooms on the homepage Sy that up all right so let's start working on the room page so if I go ahead and click join room you'll see in the top URL we have room slid now currently this page is failing because we haven't created a page for it so let's go here I'm going to say room actually I need to call it rooms I believe let's see yeah rooms and the way nextjs you can handle Dynamic data we've already done it with the API maybe you didn't notice it is the brackets so inside of rooms I can just goe and say make a new folder called room ID and then I can make a page like this and now let's just go ahead and say X ort default async function and uh we're going to call this room page like that for now we'll just return a div and then we'll kind of like add in some stuff awesome so the first thing we're going to need to do is definitely get the room ID how do you get the room ID well you'll have props that are passed in if I were to go ahead and just like console log these props you will be able to see what these are set as um now I don't know where that console log is going to oh for some reason I got to do this so the console log I think it happens on the server side of things so let's go to our server and notice that we have pams which has a room ID so remember in nextjs when you have an asynchronous page it's going to be server rendered okay so here we can say room ID is equal to props do pr. room ID and there you have it now I personally like to type these things so I would say pams room ID like this so that it's perfectly typed and we don't have an any on the top there uh we don't need the console anymore so now we know what the room ID is let's just go a and display it go back and you can see the room ID popping up down here now you're asking why do we need this room ID well we have to fetch the data if someone were to bookmark a room or share a link with a friend we don't know the title and the description and all the other metadata that might be attached to a room so we're going to have to fetch that from the database so that's the first thing we're going to do is we're going to figure out how do we get the room information let's say const room is equal to get room room ID now this is a method we haven't created yet but remember we just made that folder called Data access it has a file called Rooms let's just go ahead and load this up I'm going to say get room we take in a room ID and then we could basically say room doind first now to be honest I'm going to load up the drizzle docs because I don't remember how to find first so it says you can do the query the table. find mini also find first which does uh this is there a example of where you can do a wear Clause yeah so you can do something like this let's try this I'll say find first where and then we're going to do this equal function then we're going to say where room dot think I need to import room from the schema I'll say where room. ID is equal to room ID so the pattern is a little bit different from like Prisma um they have like this Builder object where I think you can continous to like add things onto this or you could do like an and maybe I don't know but we'll just we'll figure it out we have the docs don't be scared to just go look through the docs to figure out how to do stuff but but now we have a method we can call that should get back the room um I would probably like to call this instead of rooms I'll call it like something else but the issue is that this is called room um you know what I could just return here we don't even need to do any of this just return that'll give us back the room and we should be good so now if we autoimport this from data access we should be able to display the room dot name let's go back to our app notice that the room name pops up now I would rather click on like this one this one will probably be better working on devinder now the way I Envision this working is we could have the actual like screen sharing happening over here and then we could have maybe some room metadata displayed on the right maybe even a chat I don't know if I'm going to do a chat in this application but let's let's try doing that um let's go ahead and try to split this left and right so I'm going to go ahead and and um make a div and I'll say class name is equal to grid calls maybe we could do four I'm also going to give this a grid you also do Flex it just depends on what you want to do um grid just sometimes is easier sometimes grid is easier than Flex box sometimes Flex box is easier than grid so we'll find out this will work for our needs so we do want a on the left we're going to make a div and this will be for the video player we are not going to do yet we're going to figure out how to do that in a bit but we do want to display another panel and this will be like the info panel okay so if we were to look at this we want the video player to have more real estate like more width than the the panel right so different ways you could do this if you use flex you could just give this thing a like a hard-coded width and then maybe give this a flex grow but since we're using grid we could say all spand three I believe now this will make the video player expand up to three columns and then we have the panel on the right okay second thing we want to do is on this entire thing this div we could go ahead and say Minh is screen and then so that you guys can visualize what's going on I'm going to give this a blue I'm going to give this a class name of BG red 400 because right now it's not very easy to visualize and we could probably give this whole thing a height of 100 so here I'll say h of 100 or h of full I mean height of full that should expand it maybe I think there's like a something going on here where it's not expanding all the way that's full H screen Minh screen this is a grid you know if I actually said in in h screen here will that help it yeah that works I'm going to actually get rid of this one and there we go all right so first of all I'm going to put a little bit of gap between these things and then secondly we could probably make these like B divs with like a drop shadow so inside a video player I actually want this to have like a card inside of it and then probably info panel could also be a card too so let's go ahead and wrap this in another div and I'll say like drop shadow is that what it is drop shadow large let's try that I'll say video player and then for right now say DG orange 400 okay so what we're actually going to do is I'm going to give this a BG white of 50 for right now maybe even 100 and then inside of this wrapper here I'm going to go ahead and just give it some padding so let say padding of like eight there we go I don't know why BG white disappeared oh cuz BG white is not a color I should just say BG gray there we go maybe you can give it some rounding so I'll say rounded that's how you can make the corners be a little bit rounded and then inside of the actual card itself I can give this some padding of 12 as well so we got a nice floating card same thing with the info panel let's just go ahead and copy all this and we will just go ahead and just say invo panel this will be video player now the issue with the info panel is uh I should say call span one there you go so a little bit of tweaks we could probably like reduce the size of this I think I have like um much padding going on for these so I'll just say like a two maybe even a four this could be a four and then why is this so much padding there I think this is like I'm make this red again so it's the padding so technically if you don't want that much space here you could just remove some of the padding of either the red or the blue column I might remove it on the blue so padding right at zero or maybe even padding right to one I think it's like removing the the Shadow or maybe two and this could be padding left to two Okay and then let's just remove these colors the colors were just so you can visualize what I'm trying to think if we were to go back to what the cards look like maybe we should just make them match the card style the cool thing about Shad Cen is you can just go to the card component and you can just grab literally this whole thing and we want to make this be the styling of this so let's just drop that in this make sure that looks like a card now and I kind of wasted all that time styling that thing but hey at least you learned something with Tailwind maybe so now we got a card over here and a card over here I could have technically just wrapped it in a card anyway that's good enough so we need to put some information in the info panel so let's go ahead and first of all the padding of 12 is way too much I think it needs to be like a padding of four maybe and then in the info panel we need to put the name of the room like this let's do an H1 for the name the class name is text of extra large he maybe that's too much I'll see say base and then we will say we'll have an H2 or paragraph tag for the description okay and then we'll say this will be like text Gray of 700 maybe even 600 now for this let's just go ahead and give this a flex Flex call and a gap of four just to kind of space out some of the stuff and then we could put a link to the actual GitHub repo which I'm going to just go back to here and I'm going to grab this code paste that in Auto Import some stuff Auto Import that one why not and figure out why this is potentially undefined so it's saying room could potentially be undefined which depending on the interface you want for your function you could have this throw an error if it's not defined which might be good um or you could have some type of like State here saying that hey if room is not defined like if there's no room let's just return no room of this ID found there's different ways you can do error States in nextjs I think this is the easiest approach um instead of like having to do an error boundary personally but we'll do it like that so now if you were to go to some random ID so let's change the last number to a four no room of this ID found there you go go to one that actually exists and it'll show up it a project still shows up and I think was there something else we're storing on this um room dot what was that we'll say room. language so okay here's an opportunity to bring in something interesting from Shad SC there's something called toggles or like uh badges I mean so let's go to badge and we're going to bring in something that looks kind of like this let's just go aad and install that badge again go to your terminal paste it in that'll start installing we can just import the badge directly at the top and then we want to probably put the the language here so we'll say badge like this what's the interface for this uh variant outline so I think by default it should look fine let's just go to F finder and then it says typescript here now the reason this is like full wiing is because of the call the flex column we're doing if you want to get rid of that I think you say w. fit and that'll basically reduce the width to be like what size it was supposed to be okay now technically what we could do is we could make it more sophisticated for the tags I think that would be actually pretty cool if we were to go back um to drizzle Studio actually and for language let's just assume that this is like a comma separated list of languages so like I know my head is like hiding that let's just close that we'll say typescript what are some other cool things that we're doing we say like drizzle uh we are doing nextjs and we are also doing uh G stream just save that and now if we go back to our app and refresh notice that we get that info info back but we could split it by the comma and like actually display that stuff again this is just a hack I think potentially you want to make like a tags table and then have some type of normalization between like your tags this is just keeping it simple right keep it simple and we're going to go and say tags is equal to room. language actually I'm going to say languages and then we want to split by comma and um additionally we probably want to Loop through everything and trim any spaces so I'm going to say map I'll say language trim there we go AI came in clutch right there and what that's doing is someone were to create a room that has like spaces in between the commas it'll still work now what we're going to do is we're going to Loop over these like this go ahead and see if AI can help us just kind of do this or just do that that should be fine enough and um I'm missing a parentheses there we want to put a key here and this key needs to be the language then we also just want to print out Lang here does that make sense so now we have all these different badges for our languages now technically I should rename that from languages as something else like these aren't languages anymore these are like tags and then we can put a comma here that should be good and then for all the badges themselves we should have like a a wrapper which I think we could probably just say Flex go ahead and wrap that there and I'll say G app of two and that should space them out now we do have to tell the styling that we want it to wrap when it goes off the screen like this and um I think it's like a flex wrap you can say Flex wrap maybe there you go that look pretty good tags is a little big I might actually reduce that actually I don't think we even need tags it's kind of obvious what this is these are tags right um and then we have the project here which looks a little big as well so like I might actually text Center this and I'll say text so small not sure why the text Center is not working I could say self Center I should put it in the center there you know now I think about it let's just go ahead and move this whole thing up I'm going to put it right underneath the title that'll be a better design or technically you just put an icon up here you know you you make it how you want it to be so in the future maybe we could do like you click on a tag and that'll take you to a page that shows all the other people who are coding typescript or coding on drizzle or coding on nextjs but for right now we'll just keep it basic um one thing I do want to fix before we get into the video player part is if you go back and create a room uh for the language I'm going to rename this a little bit we're going to do a little bit of refactoring here and I'm going to rename this to tags list your programming languages Frameworks Library so people can find your content okay let's just go ahead and do that and um we probably wanted to put a placeholder in this one actually I'm going to say placeholder is typescript uh nextjs Tailwind okay so people know that just by looking at the placeholder this is a comma separated list of tags um and now that I think about it maybe the placeholder is a good idea maybe it is a good idea so that people know like what they need to put into here so let's go back and I'm going to go to here I'll say placeholder and I'll put a link to my GitHub we go for description we'll do the same thing say placeholder I'm working on a side project um join me and then finally for the name just the name of the project I'll call it [Music] devinder is awesome now technically we could probably get those tags displayed here as well so like at a top level people can see what the tags are so I know I'm jumping around but that's just the way like I like to teach I don't like to have like a structure I just kind of add things as I think that we need to add them so let's go back to we do the the the tags which where do we do that that was over here I called it languages so I'm going to change it to tags real quick I'll do a FN F2 I'll see tags that'll ref fact it I don't like how this is called language anymore so we will go to the schema we'll call this tags like this and then we're going to have to write write a migration script I'll call this tags do that and then I'm sure there's other places in our code base we're going to have to fix but I'll say mpm run DB push that should applyer changes now this gives us some options do you want to rename it or do you want to create cre a new column I'm going to go ahead and say we want to rename the column and then execute everything go ahead and restart that and I'm sure there's some places where we got to fix so let's go find our typescript errors this what is this complaining about oh I think we call it language here so this needs to be called Tags and I think our app should be happy now do that okay column language does not exist uh do I have to restart my next app to get this to work seems like you have to for some reason so okay so the whole reason for that I want to make sure I didn't break anything anytime you do a major refactoring like that like just make sure you don't break anything typescript node submit seems like it worked if I go and view this do we see those tags awesome and like I said I want to get the tags displayed here so this is a good opportunity to make a reusable shared component so let's go here and I'm going to make one called TS list PX and we can just go ahead and say export function tags list this needs to take in a list of tags and then then somehow it needs to display them so how do we get those tags well we can just find out where we use them and I will just copy this I'm going to return that whole thing import the badge here and now we can use that on our page so I'm going to go ahead and just say tags list pass in the tags that and we should be good just need to Auto Import that let's make sure we didn't break it let's go back to our main page that's still displaying now I will say I don't like this approach to um how we have to kind of like split and then trim so we could add a utility function probably honestly in that tags list component we could just go and say export export function split tags and then go ahead and just do that code there I using co-pilot so I don't want to type everything out it's kind of a pain but it's the same code we're just going to go ahead and run split tags on that and then you can kind of reuse this code and then technically we're not using this anywhere else right so we could if you wanted to just cut that put it here there you have it you might ask well why didn't the component just run this logic I'm trying to make the component not know about the way the tags are stored in the database all it needs to take in is an array of strings and it's a responsibility of the person calling or using this component they need to figure out how to get that data in the format it needs so now I can just go here and I'm going to go back to my main landing page and somewhere in this card probably underneath the description uh we could probably just put the tags in right go import that go ahead and import that save it go back to our main page and you see that those pop up now we do want to add a little bit of margin underneath the GitHub project so we're going to go ahead and just say margin bottom of four push that down there you have it um I might swap them as well I want the tags to show up first so I'm going to go ahead and just cut this put it down there and then um instead of doing the margin Bottom now I think about it we should probably just give this a class name Flex Flex call gap before and that should just space it for us I would probably recommend doing Flex or Space X or space y instead of doing margins it's just it's cleaner in my opinion but yeah so now we got some cool tags let's go back to the room and I think this is pretty good I think we're doing pretty well now for the video player part so when you try to go to a room we're going to be using something called G stream IO so this service allows you to basically create video calls and rooms and you know chat rooms as well I think it uses web RTC behind the scene but it kind of takes care of all that heavy lifting for you so I'm going to create a new app here we're going to call it Dev finder and we're going to say we want this to be in Ohio because I'm on East Coast chat data storage location Us East let's go on existing app we're just go let just create it you'll be given a key in a secret and honestly I'm going to go to the docs to because you've watched my tutorials I like doing stuff live so how do you do a video and audio call so we will be using the video and audio feature of this they have some other products as well but let's just go to the video and audio and then I'm going to go to the docs and we're going to click on react we view the react documentation and they got some good information here how to get this all set up let's go to installation first thing we need to do is add it in okay just go ahead and mpm install that they give you some example code how you can create a new room from the client side of things and we'll have to get into more of like client authentication and stuff like that so let just grab this code and see if we can at least get a video player displayed okay let's go to our room and in this video player section I'm going to make a new file here called video player TSX CU I'm pretty sure we're going to want a client component for this so I'm going to say use client and I'm going to say export function video um I'm going to call this Dev finder video because I think they called their components like video player and stuff like that so first of all Let's uh import some of the stuff oh let's just change the name of that what whatever and I am going to change it to be functions okay delete this and let's kind of look through here because there's some things that we're going to need like API key we're going to have to get an API key which I think in our application that we set up here is the API key right here so let's just say process EnV next public get stream API key and then we'll go to ourv file which is here I'll paste in and we want to grab that like this so first of all let's make sure that this is set so that we remember it and then here we're going to set it just like that double quote it cool so now we need a user ID in this case we we know what the user ID is I believe um but we'll figure that in a bit and then we also need an authentication token um now unfortunately I think if we just try to use this in our app like it's just going to not work too well with nextjs so some of the stuff we only want to run when it's been mounted to the client and the way you do that is you can use a use effect like this you might say well why we need this you have use client up here when next tries to run and pass through like a route it does its server side rendering and it's also going to dive into your clan components and try to like render static assets for that too so some of our stuff that we're setting up here we want to use in a Define in a use effect so let's just go ahead and pull down some of this um we could probably store the client yeah so I'm need to say const client set client equals this uh pull in use State here and what is this complaining about it's saying that this is potentially not assigned so we want to make sure that we only do this um when it's ready so I'll just say when the client's ready we'll do that uh same thing with the call we're going to have to say const call like that and what does a a call object have it's called call so let's just go ahead and do that this could be null go ahead and import that type and we are going to call that call like this and then we probably want to do some cleanup right so when this effect unmounts we probably want to leave the call and then client I think there's like an end method or a stop let's see what we have here we have disconnect user so leave the call and disconnect the user so some additional things we're going to need is the user ID remember we're using next off right so we have the session potentially I can say con use session and we can import that and then the session should have the user ID on it so instead of like defining this um in that we're going to have to get the user ID from session. dat. user. ID now if this thing is not defined we just want to return and not do it and then here we want to run this logic if session changes so for user you can just go ahead and say user ID like this so now if you're authenticated you're going to have a unique user ID as you join rooms and we're going to use that as our identifier when you try to join these different rooms okay so for call uh we need to also make sure that this defined now technically we had add a spinner or a loader here but let's do one more thing here the last thing we need to do is this authentication token um so the way authentication works if you're just doing development locally you have to generate an off token and they have a way to kind of do that for you let's go to authentication over here and I believe they have a token generator so let's click on the token generator and then you can pass in your user ID here and your API secret what is API secret that comes from our actual here we have the secret here we can copy it and we're going to paste that in here which I think it is already that no we're going to paste in our secret and then we want our user ID what is a user ID for our user well let's go over here let's figure that out let's go back to users and let's click on that and here is my ID so I'll copy that and let's go somewhere here it is I'll paste that in this is your token now technically this is something that you want to generate when you click join room or when you click create room and you want to store that in your browser as the page is load loading right and I think they have an API for doing that but for right now we're just going to verify this works by taking this token and we are going to just use it so let's just go here I'll paste in the token here and um I think we're forgetting to call set client so I'm going to go ahead and just call set client here that we can access it over here and this could be instead of my first call I think this needs to be an ID of the call so in our case we have the room right we need to get the room ID I'll just go ahead and pass in like the whole room information that and then this could be room dot ID so now that we have this all set up let's just go ahead and render out the video player that we are setting up I think we called it Dev binder video like this import that and this should hopefully if we go back to our app we should see it start to ask for some permissions here notice that it's actually um allowing my camera now there's a little issue I think room ID is not defined here so we need to make sure we pass in room for this effect and I'm going to say if there is no room then also probably just return oh sorry I need to do that here if there's no there's if there's no room yet then just return as well so we want to make sure that the session is defined and the user is logged in and there's a room that came back so I think it was working I just forgot to add in a couple of things um for example I brought in a stream theme it stream automatically has like this nice theme you can use for your video call session and then I also added some speaker layouts in call controls and then finally there is a style that we have to import which I forgot to do so let's just go ahead and import The Styling directly from stream.io video react SDK so now we should actually be able to see like a camera webcam and we can actually change our camera here I don't know why it's picking my OBS virtual camera here we go now we can actually see myself I'm going to switch over to dark mode so it looks a little bit better so right now we use their little like web API to generate these tokens for the authentication we actually want to do this on a server action so that we can get real tokens based on the user ID so here is an example how you can do with their node API so over here they tell you how to provide a token provider so when you make a new stream video client and pass it a call back function where are we making the new stream video client right here just pass in the token provider this and what we can do here is basically call a server action so let's say generate token and we don't have a server action defined yet so let's just make one here I'll call call it actions. TS and I'll say use server export async function generate token and for this to work what we need to do is I believe there's a nodejs SDK we could basically just pull in we can kind of just call these two lines of code let's just grab it all just so we have like a reference copy that I'll paste it in there and there's a couple things we need when the API key which we have already um that's already in next public stream API key so we could probably just say process env. that we need the app secret so we don't have that yet so we need to make sure we Define that I'll say get stream secret and probably put key at the end there and that's on our dashboard so if we go back to our dashboard here we can click on this and then paste that in there and I'm going to go ahead and just update this one as well all right and stream chat we might have to import something for that to work but but then let's take this and we'll say what do we call it again get stream secret key call it that now we can just use that and for user ID we're going to have to pass that in probably get the session which remember we made that helper function inide of the LI off folder we get the session and we should be able to get the user ID from that session um if there is no session we probably want to throw an error and then we have session dot oh we need to await on it don't forget the await we'll say session. user. ID and should be good there now we just need to return the token and then also fix This One Import that we're missing for stream chat where is stream chat defined I'm not sure I think we have to import it somewhere so let's go to backend and they are using stream chat all right so I don't think I have that installed I'm going to install it here stream chat and that should allow us to import this thing um how do they import this just like this import it like that I believe okay so now we have a server action I'm going to add action at the end of that function name and then we're going to call it like this and then we're going to pass in um do we need to pass anything in I think we're good think we can just do this all right let's get herid that hardcode token and let's make sure this all still works um well I'm going to delete the token that was hardcoded and now just give a token provider and so when the stream starts initializing it's going to caller function which should invoke the server action get some token back and hopefully set that up so let's make sure this is still working fine and go back to Face camera awesome and I would like to test this out I might go grab another laptop so I can test this out um and have multiple people connect to the same stream but for right now let's just commit what we have cuz we did a lot of changes I don't want to lose these changes so I'm going to go over here and I will say adding in the video component from stream go ahead and sync that up all right so now let's try something pretty cool with this I have another laptop next to me and I'm going to go ahead and see if I can connect with that laptop to this same chat room all right so I am logged in uh on another tab with a different email account so I'm going to try to join the exact same room and let's see if this works go and click join room and now we have two users who are in the same room I'm just getting access to my camera and stuff like that all right so on the other tab that I've opened with my other user what I can do is I can actually share completely different window or screen so in our case I'm going to share my vs code editor and now I can see that pop up over here so right so I have another terminal open I can just go ahead and like share what I'm working on you can hear me talking and this is actually pretty cool this took very little effort to get screen sharing going and we have a ton of built-in functionality with the screen sharing right I can block people I can turn off their video turn off their audio do full screen and stuff like that so so one thing that you'll notice is like the video has like a uid down here I think we could probably make this better and have it displayed the name of the user so let's go back to where we set up this video player and the user itself we can pass in some cool information so for example we could pass in the name which should be on the session and we can also pass in an image which again should also be on the session um let's try to figure out why some of the stuff might be undefined I think name is potentially undefined so we could say unknown and then for image yeah we'll just go ahead and um do this if it's not defined we'll just say un find like this maybe you it's just to fall back undefined on both of these okay so now hopefully it says my name down here awesome so let's also verify the image is working so there's components that stream will give you out of the box for example one is called participation list or participants list which kind of looks like this and this displays your name and your image and stuff like that so something that'd be cool if we can actually like get this to display let's go down here and let's just go ahead and put it inside a stream call put it on the right over here I guess and let's import that and see this will show now it does look like it needs an onclose method so I'm going say on close and for right now I'm going to see if I can get away with like just not doing anything I'll just say undefined okay so now let's go back to our app and there should be a participants list that shows up down here we can like search over everything um we can do various things with people I can close it which I guess we'd have to kind of use our own react state to make this like closable and just like not display it so far I really like the stream Library like this was super easy to get a lot of components out of the box just by importing them and displaying them and I think if we restructure our app a little bit we could actually put this and Nest it inside of the video component here which allows to give us more flexibility of like having this thing um in the participants list maybe being down here if you wanted to I won't dive into like that refactoring just yet because there's a couple things I want to do the first thing I want to do is if you were to close the video I want to kick the user back and take them back to the homepage so when they click leave call let's try to figure out a call back that we can invoke when that happens so over here there's an on leave callback function and this will be pretty easy to get set up all we need to do I think is just say const router is equal to use router import that from next navigation and then down here when you on leave you can say router. push and go back to the homepage because I think it's going to automatically clean up when we leave this component and unmount the client connection and stuff like that so let's click this and let's go back to the homepage we did get an error cannot leave the call that has already been left I'm actually going to do here I'm going to say catch and then we're just going to log the error we don't want that error to get uncaught and Bubble Up and then same thing here I think this might be a promise um which we could probably only call like this so basically just log any errors that happen and um yeah that should hopefully work probably want to just return from there too let's try this I'm going join the room and I'm going to go ahead and just let it connect and then I'm going to leave and it did log it out but that's fine so another thing that I think would be good to do is I notice that when you log out up here if I to click sign out it doesn't kick us back to the homepage it just like logs us out and then this view thing just like crashes because it EXP you to have a user ID but now you just like deleted your session it doesn't really know how to clean up this view so let's go to the header and let's add some logic so that when someone clicks on log out or sign out um which is here we want this to have a call back URL probably I think you can do this and we can say call back URL and we're going to just say go back to the dash board so that this doesn't happen um I'll click sign out that'll sign me out to go back to the dashboard and another thing I noticed is that this Avatar and sign in should not be visible at all when you're signed out so let's figure out where that is being displayed count drop down first of all we don't need a signin button here I don't think that even needs to be there so we're going to go ahead and just like delete all this stuff okay so for account drop down we only want this to display if session. data is defined we haven't even brought that in so let's just say con session is to use session like that and now that'll be gone that will not show the drop down unless you're already signed in but we now don't have a signin button let's kind of add that in I'm going to say if we're not signed in we can just go ahead and bring in a button that looks like this and we really don't want to do that let's just say this let's see what happens cool um let's try it sign in so a couple of other things I want to try to implement um I kind of talked about this before but on the search page if there's a way to filter based on keywords or tags I think that would be pretty cool so let's go up here and let's add like a search bar just so that we can filter down a little bit so I'm going to go to find Dev rooms this and then we're going to add a form here called search bar and then we're going to go ahead and make a component just do it right here in the app since this is going to be in the same folder search bar TSX export function search bar so I do want to use like a form so remember how you created a form over here we had to bring in like this form component do all this stuff so I'm going to take that and we're going to reuse a lot of this stuff copy all this honestly okay and then we're going to take all this stuff and do this and we're going to delete a lot of stuff so I'm going to delete right room action comment it out comment that out we don't need all these we just need search okay and then we don't need all these form fields we really just need one so delete that have a button that says search this will be called search we'll go up here we'll call this one search it can be a Min of zero if you want to clear it out and we'll say search by keywords okay and um we don't need a description over here let's just see how this looks if we were to use it we're not importing it yet but we do need to bring in the search bar component and import that okay and we should see a search bar pop up there it is and I might actually get rid of the label so let's go back here go find the label we don't need a label I'll say search or filter rooms by keywords such as typescript xjs python that type of stuff okay so now when a user were to type into this thing and click the search button we need to do a query so I I am going to style this a little bit I'm going to move the search button to the right and the way we can do that is on the form itself we give it Flex that should put them on the safe page and then the search bar I think we just make it a little bit larger I think this could be like a width of 300 pixels maybe or maybe like 240 pixels and I should probably put that on the input itself like this 340 okay it's still pretty small 400 awesome and then on the form itself we're going to just put um you know not on the form I'm going to do it down here I'm going to do margin bottom of 12 like this a little bit of extra touches we should probably add like a magnifying glass icon inside a search let's go over here let's find the button I'll say search icon okay um over here class name margin right of two probably add a little bit of space between the input in the search bar and the way we can do that it's just a gap of two here I think my head might have been hiding okay there you have it so the functionality when you type in something here and click search we want it to actually probably kick off an action to get the new data or just refresh the page that has like a different search criteria so in our case if I were to type typescript press search I want that to reload this page and redo the query okay so let's go here and so on click what we can do is I can say router dot oh I don't have router let me import it let's say con router is equal to use router like this and then I'm going to say router. push and we want to go to the same page or we're going to tack on a search query string like this I'll just do a like that maybe I'll call it search and then also if search is not defined so like I'm going to say if it is defined we're going to go ahead and use it otherwise we're just say router. push go to the go to the same page with no query string okay so now if I type in typescript press submit notice that it did add a query string here that's cool because now a a user can bookmark this they can share this with people and then we have state that's embedded in the URL which makes it a little bit easier for us as developers because now we don't have to like store this in state and do all that stuff so how do we get this to actually redo a query when we change the query string well remember on the props here we have pams actually I don't remember what it's called let's do props let's say console log props and this could be any now I do think I need to load up my next app so I can see we have a search prams notice that this popped up it says search prams search of typescript so we have that information there and I can just simply do this I can type this and then this will be search of string make sure I have that right all right so now instead of calling get rooms just by itself we can actually pass in search for rams. search and if this thing were not to be defined it would just pass in undefined so now we can actually say search is a string or could be undefined we don't know and instead of saying find many we need to say where so we could say where and then we'll say EQ and then we're going to say room. tags now instead of EQ I do think we want to go to drizzle and like figure out I think we want like the like is a way we can kind of search over and see if it has a string in it um unless there's something else we could potentially do I think like is probably fine I'm going to import like and then I'm going to use like instead and we're going to do like this and then we'll do interpolation here and then we'll say search Now search is potentially not the defined right so if it's not defined it might make more sense to actually make this be different so I'm going to say const where is equal to if search is defined we'll do that otherwise we'll do nothing um and then I think we can just pass that in hopefully doesn't like that so actually we can say uh we'll set this to undefined I think that'll make it happy so let's let's try this let's go back to our app I'm going to go ahead and just type in JavaScript click search typescript click search clear it out click search and um yeah it looks like it worked good and now I think what I'm going to do is if you are on a page that you're already like searching a criteria I might just have a button that says clear filters that you know that you actually have like a filter typed in it's not too apparent if you were to delete this and you're like I can't see all my data right so let's go back to search the search bar here and we're going to have to pass in first of all the parameters which I think we can actually just get actually I can say use search prams do that and then over here we're going to display a button if search is defined like this and save that and have to do a g on it yeah that should work and then if uh we'll call it clear which is just going [Music] to going to clear the search form yeah this looks good so let's try this okay um let's click clear and see what happens yeah so it deleted that it cleared out this I'm going to say type script press search press clear there you have it last thing I do want to fix because there's a bug if I were to just refresh this page notice that although the clear button does show up typescript is not here so we want to kind of map the query string to the input so let's go to our input here and I think the way we can do this is default value we have the query so we can say query. G search otherwise we can just call it default it to um an empty string right so now if I were to refresh the page that'll get set in and I can just clear it and if I refresh it still works fine all right let's just command what we have now I'm going to go ahead and say adding the ability to query by tags all right so one more thing that I think could be really beneficial is now that we have the ability to filter based on tags what if you clicked on one of these badges we could have it automatically route to this page with the filter in the URL so let's go to our badge actually it's called a something list tags list and so like when you click one of these badges I'll just say unclick we're going to go ahead and just do a router. push need to make sure I bring in cost router isal to use router this and then router. push is equal to and we could just go ahead and do the main page like this and I'll say search is equal to um Lang now I let me rename this from Lane to tag I think that was left over like this okay so now anywhere in our application which okay this needs a client component so I'll say use client at this point it's complaining that split tags is not a function it's because I added used client here I might just make a utils and I'll just call this like yeah I'll just I'll just put it here in utils I'll paste that in Split tags um and now anywhere where we did split tags before we're going to have to fix need to import this from a different location like this and then I think over here we probably need to not import it from there okay so now we can click on this one notice it takes us to typescript so there is a little bug with this when I click on typescript notice that it does actually filter down for typescript things but it's not putting the typescript filter here let's try to figure out what's going on there um in the search bar I mean we get the query here so I think if I were to just go ahead and like print this out maybe it's not um doing that when you click on let's say node it does run I think hold on let's also do this I'm gon to say get search we may just have to add an effect I think it's like getting confused yeah so this is only going to run once because it's state and like it's going to be probably behind the scenes it's probably like some State somewhere that's not being unmounted so we're going to say use effect and we want to listen for when the query search were to change I think that's how we can potentially do it and technically we could just say like search is equal to that Che to see if this thing actually changes go ahead and import use a effect and what we're going to do is we're going to say form. set value we're going to use that search we also probably need form okay that seems like it's fix it now is that the proper fix with the use effect not too sure but if it gets the job done it gets the job done right now the cool thing about this is that since we're using a reasonable component you were to click on for example typescript here that'll take you back that'll disconnect you from the room and then you can see all all of the dev rooms that are running with typescript keywords now I would like if this was a cursor and not a like a select so let's go back to tags tags list and on the badge itself I'm going to say cursor is a pointer and because this is clickable it might be better to like make this a button instead of a badge or you can probably add a um I think you're going to add a tab index of zero so that now you can actually like tab on it you could also probably add an area roll of button just make it a little bit more accessible so I can actually go and like click on different stuff actually I can't even press enter right I should be able to press enter so I think what I might do is this thing have an as child it doesn't seem to have an an ass child so actually I wonder if I can just like make a button and wrap this whole thing like that click on the button here there's different ways you can hack a HTML CSS and whatever make this work now we have these if I were to enter on them it works do I really like this I think a better approach would be look at the badge itself and just grab this and grab the whole class names here and honestly like don't even use the badge component anymore because I don't think it's the most accessible approach think we're even using a variant okay so now notice before is like the outline wasn't directly on the button but now it looks like a button and it acts like a button the other wrapping a button with the badge was kind of a hack so this is something cool to point out though is that everything in Shad Cen typically it exports the variance so you can apply the same styles to whatever Dom element you want just by doing something like this which I think is really nice because now it's like I want it to look like a badge but I don't want to use the badge component all the same styles are accessible to us we just bring them in cool so now if I go and join the room and go to this I can kind of go back and awesome let's go ahead and commit that as well so I'm going to say better uh I'll say click Badges and I'll submit that so let's continue adding some more features I think one thing that would be pretty nice is the ability to keep track of the rooms that you have created and we could have like a separate route for that potentially and just show all the rooms that you created let's go back to our nextjs application and I will make a your rooms endpoint and it's going to be kind of similar to like our main page here where we kind of like query get all the rooms and then we display those so let's see if we can kind of use that approach so open up this page over here and we can just go ahead and copy all this code and we are going to go to let's go to your rooms we'll say page. TSX and we'll paste that in and let's just kind of refactor some code here I'll say your rooms page and at this point we probably want to reuse the room card okay so now we've reached a point where we have like a shared component and I think it makes sense to go over here and just make it here so room card TSX go ahead and copy all of this code and I'll paste it in there delete anything that's not used and then export it and now let's go over here and we don't need to Define room card in this file and we also don't need to Define it in this file cuz I think they're going to have the exact same style to them right so let's Auto Import room card and that components directory let's also Auto Import it from the other file and just do a little bit of cleanup here this have to go up a level I believe some of the stuff would go away okay let's go over here make sure this is cleaned up and then we'll also go over here clean up this awesome so here it it says find Dev rooms I'm going to say your rooms we could keep the create room button um we don't really need a search bar anymore I don't think I mean like how many rooms is a user going to have hopefully not that many um but we're going to change this fetch method instead of saying get rooms I'm going to say get your rooms or maybe it make more sense to say get my rooms since like we're authenticated um maybe I'll just say get user rooms how about that that that might make a little bit more sense and so we could make this method we go over here to data access go back to Rooms I'm going to go ahead and copy this whole function here and then I'm going to use get rooms get user rooms here all right and we don't need the ability to so we can get rid of that but what we do need is we need to get the session so again how do you check if you are logged in I can say const session is equal to get session and make sure you import it from the right directory wait on it and then if the session is not defined obviously we should throw an error or sometimes what you could do is just return an empty array it kind of depends on your use cases um yeah so now let us do a wear Clause so I want to make sure that it only get the rooms I can bring in EQ which is that already there yeah we already have EQ from drizzle and we want to get room. user ID and then make sure that matches the currently logged in session. user. ID and we don't need search here keep it simple now we got a method that is authenticated only a logged in user can hit this endpoint and we can use it right here so just go ahead and Auto Import it that should give us back all the rooms that I own that I have created and also we don't need search parameter so technically we can delete that delete that method and now we need a way to let the user be able to get to that link so I might just put it in the header let's go to the header here and let's find um a place to put a link so right now we have space between if we put another div here we could typically have uh the links here or if you want to do like nav um if you want to do semantic HTML we can make a link and we can have that go to um what I call it your rooms and then it could say your rooms that and let's see if it shows up so now we have a your rooms link unfortunately there's not really good styling so we should probably style it with some class class name equal to hover underline simple easy enough one thing I will say is that like you notice that we have all these different like custom hover Styles you may want to abstract the way a link component and wrap the next link if you have the same style you're using out through your application I'm not going to do that just yet but I want to verify if I click on your rooms it should take us to a view that just shows the rooms that I have created same thing I should be able to click on create room that'll go to the for where I can create a room awesome now this wouldn't be a good tutorial unless I did all the crud methods right so we should probably have a way to delete the room if a user creates it so maybe a trash can or like I don't know some type of delete button close room maybe so let's go to the room card and we have to kind of modify this just a little bit this is the issue with having shared code is that I want to add additional things to this card that doesn't need to display on this card and so when you try to make a generic component what you end up doing is you just like tack on a bunch of extra like if statements and stuff like that to know if you should hide or show the delete button um so now I'm kind of second guessing if this is what we want I'm just going to go ahead and move it back I don't I don't like the idea of having like this anyway let's just go ahead and copy this whole card now at least we have a component that we can just like um just do this user room card and then the difference is we want to add a button here that probably deletes so I'll say like delete room or yeah I'll say delete room and then we'll give it an onclick and we need it to do something when the user clicks this button so let's verify I think I need to refactor a little bit of imports going on here so this needs to be slash uh user room card and I'm going to rename this to user room card over here and that could be called user room card and this could be used over there and then on the page itself we need to go back and change this to just import directly from room card I'm curious leave a comment what your approach would be some people like making components that have like a bunch of different if statements and Branch logic in it um I have found that that causes code to be a lot less maintainable versus just copy and paste the entire thing so every page can be managed in isolation it just makes your blast radius smaller when you like make a change and ends up breaking in every place but it does add some extra work like if you need to change the style of the card yeah you got to do it in two places now and that is the tradeoff all right let's go back to my rooms and I want to make sure that that delete button shows up which for some reason it's not so let's verify am I importing user room card I am that goes over here we have a delete room button that should have shown up um I think it's because I'm doing as child let's get rid of as child breaking because I forgot to add use client at the top also add that to room card that all right so that should make nextjs happy now we have a delete room so something I haven't shown you yet at least I don't remember showing you I might have is a variant we could just go ahead and add in like a danger or destructive to that so now it's red it says delete room um obviously I like to add like a trash icon to it all right and then make it a little bit smaller I could say width of four height of four and um margin right of two why not cool and then also put a little bit of gap between these two so let's just go ahead and add some Gap here which I'll say class name I'll say Flex gappa 2 how about that now many applications will have confirmation right now if I just click this we don't want it to just delete the room we want to show a modal and give the user one additional confirmation that hey are you sure you want to delete this room you probably seen that in many applications the cool thing is that's very easy to do we could just load up a dialogue here so let's go to Shad Cen we have a dialogue kind of looks like this there's also an alert dialogue which I think is actually more what we want okay are you absolutely sure cancel continue and that's what we're going to pull in so let's just go ahead and grab this alert dialogue and we're going to install it we've done that 50 times already we know how to do it and then we're going to import this whole dialogue and just put it directly in the user room card okay just paste that stuff in and let's grab this whole alert dialogue and we can go ahead and just put it right here now there are some issues I run into like um typically your alert dialogue has a trigger and the trigger I think we could put this whole button here let's just go ahead and paste the button here and let's see if this works so now if I were to go back to our application and click delete room see how fast that was got a nice alert dialogue popping up super easy to do um and now what we want to do is say continue or cancel we probably want to rename this a little bit we could probably say yes delete all right let's save that so it says yes delete and then when we click it oh we should probably re rename this so this action cannot be undone this will permanently remove the room in any data associated with it there we go and so instead of putting the onclick here I was thinking about like deleting on this button click but now what we want is we need to do it on the action here so I think we could just simply say on click and we can do the logic on the action itself but I do want to double check are we on the right path are we doing this correctly let's go see how they do it [Music] um you can also go up here and click API reference and that'll take you to radic because what this allows you to do is see if there is something that we can listen to when the user confirms um onop change okay button submit um yeah I think we're doing it the right way so yeah I'll just simply go here and we need to delete the room now how do we delete the room well we're going to have to call a server action which again let's just go ahead and make an actions. TS here and then we're going to say use server and I'll say export async function delete room action okay now we're going to have to call a data access method let's go down here and we're going to make one called a export async function delete room and then we need to somehow use drizzle to delete a room so it looks like you can say query. room dot um actually you can't let's say delete okay and then let's do the name of the table so that'll be room and I do where that the syntax we need to do let's also pass in room ID so let's say room ID and this will be a string so hopefully y this will delete the room and um now that I think about it I I don't like how the data access layer has knowledge of nextjs like this should be that layer of extraction that I told you about but unstable no store is a next thing so what I actually might do um I'm getting distracted right now but I think this is super important now that I thought about it is anywhere we're calling get rooms we really should just basically call no store inside the react component itself instead of our helper function I I think that'll make the code uh better so we can also do it here they get user rooms find out where we're calling that go ahead and say no store are we calling it somewhere else nope uh get room do it over there import that move that to the top cool and then finally that we should be good okay so the delete room action this needs to call I'm just going to say await delete room and we need to pass out a room ID which we don't have and we also need to authenticate we need to make sure that we have the session like this get the session from that Library there is no session we're not authenticated and then we could simply make sure that the room ID is passed in here okay now we also want to make sure does the user have access to this room so did did the user create this room so let's just go ahead and say con room is equal to a wait get room asset the room ID and then I'm going to say if room do user ID is not equal to that session ID we're going to throw an error and then finally we can call delete room U which we need to import so let's import it from the data action and now we have authentication and authorization so like make sure that the user who is trying to delete this room actually exists on that entry in the database so we can go back to the room card here and what we need to do is call it so I'm going to say delete room action like this probably pass it the room ID okay now there is one more thing we have to do here we need delete the room you need to make sure that the page you're on refreshes so we can say revalid date path and we're just going to revalidate your rooms like this just so that I mean this action should only ever be called from the your rooms route we want to make sure you revalidate that let's try it out so these are the rooms that I own if I were to click it we get a modal you click yes and now it's gone and if I were to try to do that behind the scenes with another user who doesn't have access to that room it would throw an exception or an error for that user as well so let's just delete these things pretty cool so we have a way to delete and now we can actually join the room and we can potentially edit um the room and there's so much stuff we can add to this I mean this is just getting more more fun to work on so I think another thing we need is middleware and also probably hide this if you're not logged in so you shouldn't be able to go to this route unless you are authenticated because if you're not authenticated well like what should you show here so I could kind of demo that if I were to sign out and then go to that page notice that it just crashed is because you're not authenticated you shouldn't be seeing this room at all to begin with so one approach you can do is use a middleware okay so inside a source we're going to say middleware dots and we're going to go to the next off doc cuz I don't remember how to do any of stuff off the top of my head so let's go to search middleware let's go over there and it looks like you could just basically do this so if I go ahead and say this copy this paste it in you can specify in this matcher what routes you want to basically verify that you have to be logged into view so in our case we could say your rooms save it and if I did this correctly sometimes you have to restart nextjs um let's just go to slou Rooms click it and there we get redirected to the login page because you just hit a route that you should should not be able to access unless you're authenticated and again if you don't understand the reason behind a middleware it runs before the actual route logic starts to run okay so if you deploy this on versell or some type of deployment that has Edge it's going to be very quick to check to see if the user is logged in and then if not they're just going to get redirected to that login page so it's just a nicer user experience versus sometimes you might have seen an applications you'll go to a page that page starts loading or has a spinner and then you get kicked out of that page back to another page it's kind of a kind of jarring and abrupt so metalwares can help reduce that issue um second thing we have this your rooms in the header up here let's go to the header I'll say your rooms this should not show up um unless you're logged in right so let's go over here I'm going to abstract this away instead of session. dat I'm going to say const is logged in equals to this and I'll double negate it we're going to kind of use that because I think that's easier to kind of read and then also if we're logged in um we could just play that this um another thing we should kind of do is we probably want the user to be logged in um to even be able to view a chat room personally I don't know that that's kind of up to your discretion if you were to build this application like how would you do it to me I think it's good to get people to log into your app um just because once they're logged in you can can easily delete their account or ban them if they're doing something malicious versus if you just let guest people do stuff you got to worry about a lot more like malicious activity um so what I'm actually going to do is I'm going to say browse and that could just go to dashboard and we're also going to update the middleware and I'm going to do a little bit more refactoring where at some point we're going to need a landing page if you were to turn this into a real product you want a landing page that people can view you have like a video you have some testimonials you have screenshots and stuff like that so having the root of the app display this probably not what you're going to want when you go to production so what we could do is I could make a new folder called browse and then we'll have this link go to the browse link and then we're going to move the room card in there search bar and the page let do that the header could stay where it is right here and hopefully now the homepage has nothing so we definitely need to go back and add page. TSX there we'll say export default function homepage or I actually like calling it The Landing Page um it's like a better marketing term for it I think okay so now we should have a landing page show up and we probably want to have like something that says like get started and stuff like that but if you're logged in we can go to a browse page which we need need to go and update the middleware as well and make that authenticated let's go to the middleware just go ahead and say slash browse super simple and now you have to be logged into that page too and yeah I think that's good so do you want to work on the landing page I guess we could work on the landing page I'll show you how I typically do that since we are using Tailwind I would recommend finding a collection of Tailwind components there's Tailwind components.com which is like I think Community collection of components they're they're pretty subpar I'm not going to lie so tail and UI you can buy a subscription and you can start using some really nice components for your entire application so like if you're go to templates I'm sorry yeah go to components go to documentation and uh you know how do I get how do I get the components house components oh I just had to scroll down okay so going down here um obviously there's all these different sections some of them are paid some of them you have to upgrade to get access to but they have a landing page um so like the hero section is typically what you consider the landing page and they give you this free to use one right everything else is going to cost money um but if you're not really keen on design and spending a lot of time like trying to make your UI look nice I would just grab some existing markdown from this app so I'm going to grab all this and we will kind of gut all the things we don't want so let's paste that all in okay maybe I should have clicked this copy button that probably would have been a better approach okay um and there's some things that we need to get rid of right so we don't care about navigation here because we made our own header don't care about that or that let's go ahead and just scroll down this whole dialogue can go away save it a little bit and let's see how this looks after we clean up of the messy things all right so let's go back to devinder and here we have it we have a nice landing page and again you can keep on grabbing sections from not just Tailwind UI but like you can find other Tailwind things I think uh flow bite is another one I've seen and then we can kind of get rid of like all this other stuff like announcing you don't have a seed PS funds or anything so delete that data to enrich your online business I'll just just go ahead and say find other awesome devs to pair with online and then for the description I'll say this platform is for sharing for screen and working with other random developers online so that you can work together I don't know not a I'm not good at this marketing stuff but there you go get started learn more we don't need to learn more page let's just delete that get started we definitely want to add a next link over here like this and we should probably just we could just hack this to take them to the browse page because again we have the middleware set up so now if we click this It'll ask us to log in there's like a Tailwind thing up here we should probably get rid that Tailwind image coming from that um this whole nav bar just let's just get rid of it we don't need the header cuz we did our own remember and I'll call this The Landing page again that got kind of Lost in Translation some additional things is like why why can we scroll right now it feels kind of weird that we're scrolling and then also the dark mode support is kind of weird like why is this whole page white it's hardcoded the BG white probably shouldn't hardcode that and then also the header itself if you look at the header it's like underneath these little decorative things but we can go to our header and we're going to go ahead and find the navigation [Music] right here I'll say Z of 10 that should hopefully pull it up above which it did not so we also need to say relative there you go so now it's above and then for the text here we need to kind of add some dark mode supports let's go back to our landing page and they have some hardcoded text Gray stuff here so in dark mode I'll say text of white you go um dark mode I'll say text right of 200 and get started looks fine yeah let's just try this I'm going to switch it back to light mode make sure it still looks okay back to dark mode there you go and then we could probably put like a an icon right here right take our devinder icon and just put it right here above that text so let's find that location looks like it's right here we can say image and then we'll go ahead and say source is equal to SL logo PNG and then width 100 height is 100 alt is devinder logo and I don't think it's called logo what do we call it we call it icon let's change the icon there it is probably make it a little bit bigger and then for last name on the icon or the image we could say block or sorry inline block that should be able to allow us to center it and there's like a bunch of space here some padding or margin I don't know we need to get rid of that just give it a 12 instead of whatever that is there you go awesome so let's click get started I think this should be good enough and log in sign in with Google and we're back to being authenticated the header could use a little bit of space between this so let's go back to the header here and we're going to find out those links so obviously we should on the nav itself we should say Flex gap of four maybe space those links out a little bit there you go and you can kind of go between those awesome so some more functionality I think we need is the ability to edit some of the stuff because right now once you join the room like it's just it's stuck there you can't edit it so how you could do this is add an edit button or add like an edit icon up here we could try doing that and we also need like an edit page so let's go to your user room card here and let's try to find out where working on devinder there's like a title somewhere here here it is inside the header itself I mean I'm just going to go ahead and put a button like this it's going to have an icon of pencil icon is that what it is pencil icon here we go and sometimes just having an icon is good enough people can know that it's like something you can edit but on here I think there's a way to say like variant or size I think we can say like it's an icon type okay there you go and then I'm going to give this some absolute positioning so I'm going to go ahead and just say button class name is absolute I'll say top is one right is one and then here on the card header just give this a relative this is kind of how you can like make stuff be floated on the top right of a card um maybe even give it more than that I'll give it a top right of two do this just to move it in to the bottom left a little bit um yeah so now if we click on this thing we should be able to go to an edit page so again how do you make it a link well you can say link here and then we'll go like this and so so then we'll add an hre to this and we'll say like rooms um you know I'll just call it edit room simple of enough then we'll just interpolate the room ID like this what am I missing I'm missing curly braces I think okay so I click on this it should take us to edit room which isn't defined and so now we need to add it so let's go to uh where do we create the room let's just copy and paste this whole thing and I'm going to call it edit room also the middleware we want to make sure that the edit room is defined as a authenticated endpoint or sorry oh I was hiding my my head behind that sledit room okay now if you click this hopefully it'll show something didn't show anything for some reason oh my bad I need to do the room ID room ID can't forget that let's just move those components into that directory there and now should work I hope there we go so again this goes back to the whole like we already have a crate room that has a form that has like the exact same stuff why not just reuse it and again my warning to you is I have done that in the past you think you can just like reuse the same page but then a business requirement comes in and changes like one little thing in your edit room form and then you have to go and like just hack together all these components to like allow it to show certain things and hide different things so copying and pasting um is my friend so let's rename some of stuff instead of create room we'll call it edit room and then we'll call this edit room form we'll go here and we'll kind of rename some of this edit room form on submit this needs to call probably an edit room action which we haven't created yet and then inside of actions we'll call it edit room action and now that I look at this file I notice that we have like the old approach of just directly integrating with Drizzle um again we should probably make a a wrapper here so I'm going to go to rooms and I'll say like export async function create room and this thing needs to to do something so like it would have to take in a room data which would be what this and then it also needs to take in a user ID to be a string and we don't want it to know anything about the session so let's just go ahead and import some of the stuff so let's go back to the create room form and make sure that when it calls the create room action that we actually call a wait rate room we pass it the room data and then we also pass it the session ID probably delete that one too all right so same thing with over here uh instead of edit room action we're going to say await edit room and that probably needs to also do something similar where it takes in the new room data and it takes in the session of the user ID um but we don't want it to emit the ID cuz we know what the the room ID is right in fact we could just pass in the whole thing just pass in the whole room I think that should be fine and instead of saying edit room here we're going to call a new method that we're going to copy and paste from this one the edit room this needs to take in a whole room object and the difference is that this needs to do a DB uh is there like an update yeah we'll say update room and then we'll say dot set think we could just go ahead and just pass in the whole room data room data and then we could say where and then EQ room. ID is equal to room data. ID yeah we don't need user ID any in here anymore okay so now we can call edit room like this we don't need to pass in the session but what we do need to do is verify that the person trying to edit this room has access to it that sounds pretty familiar right we already have a delete room action so if you go to the um which one do we want probably the your rooms we can go ahead and just do this I'm going to copy all that paste it in this will be room data. ID go ahead and fetch back the room from the database we verify that the user trying to modify that room has access to modify it then we update the database with that information and then we probably need to revalidate um you know what the only way you can edit this is if you go to the edit page I think we need to say redirect like this and I think we can just go back to to SL your rooms and then maybe do we need to revalidate the path too this I don't know do we need to revalidate path we probably do someone will probably leave a comment and tell me that I don't need to do that so feel free to do that okay so all of that need to just go ahead and update some of this stuff so this is complaining because it doesn't have the room ID and technically we we know what the room ID is right because this is in the path parameters but we could say const [Music] um use pams I mean we've done this somewhere else right we can say like prams is equal to use prams and then we can say prams do room ID and we could just go ahead and spread ID of room ID here and that could just also attach the values that'll make that happy I think oh this definitely needs to be a string though um I'll say as string you probably want to make sure that um the user typed in the string correctly it's also missing the user ID so I I think let's go back and change this a little bit I think we do want to emit we want to emit the user ID and I think that should be okay and then what we do is when we get back the room um honestly we could just probably spread the entire room here spread it with the room data so basically combine these two objects this one will have like the new information on it actually that won't be too secure I'm going to spread the room data first and I'll say user ID is equal to room. user ID because we don't want someone to like try to overwrite the user ID um otherwise that would be pretty bad remember this is just typescript this isn't actually like validated with Zod or anything someone could actually change the user ID and send that in the the payload request and so we want to make sure that when we edit the room we pass in all the data that the user sent over but then we hardcode the user ID so it never tries to update the user ID to something else and there's other ways you could do this like you could say um if you wanted to be more like specific about that you could just do room. description isal to room data do description here and you can kind of by hand update things this is just like the same approach to say like just overwrite everything but make sure that the user id never changes um and you could probably do more things with like Zod validation so that like you verify tags is a proper like string that has comma separated list values in it uh but let's not worry about that just yet so let's go back to edit room make sure this thing all looks like it's good so I think the only thing that really changes here is that when this whole thing runs it needs the initial room data okay so we should probably say room and make this whole component require the room data and so inside the page we know how to do that we can say con room is equal to a wait get room and then we can just go ahead and say like uh I for how to do that is it just like prams we say ps. room ID and then we'll just say prams is equal to that looks good add an async here and then we'll pass in room is equal to room now it's also saying that could potentially be undefined so I think if this is undefined we could say if there is no room then we're going to just say return room not found and why is this complaining it's saying that property room does not exist on that I think I must have messed up my props I did this needs to be looking like this okay and now that we have the room and we know it's going to be defined we can simply say room. name say room. description room do hiub repo and also room. tags okay so we're basically just setting up the form with a bunch of default values this could potentially be null so I think we need to fall back on empty string here and let's try it out so if I were to go to this room and just refresh notice that all the data is already added in pretty cool and so if I wanted to change this and say like you know let's put some exclamation marks there click submit that I don't know what that just did it just definitely redirected us back to the homepage oh because I let this in here um we don't want to redirect in the client action there but let's see if it did update the room so if I go to browse it did add the exclamation marks and this is too close like I think I need to add more space there I'm going to go ahead and say gap of eight there I almost misclicked so I want to add a little bit more white space let's try it again so if I go to your rooms let's edit this and notice that it didn't actually load the correct data because I think next is going to cach data right if I did a hard refresh I bet you it work but I think there's something that we need to kind of further do in the action let's go here we need to revalidate your rooms but we also need to revalidate path of the entire uh edit room link like let's do this and let's pass all this in I'm not a fan of how you have to do this nextjs I'll be completely honest with you I'm just not a fan of it there are probably ways that we can um oh yeah we probably need to say no store here make sure you don't forget that probably also in crate room too like honestly I just I like adding no store to everything so let's try that again I'm going go ahead and just edit it click submit there we go it it updated go back to the edit it did update want to make sure this is all working that's working pretty good let's just go ahead and commit because we made quite a lot of changes I mean we we remov stuff round we added middle Wares we added the ability to edit I don't even know what what else we added oh we added your rooms we've done quite a lot so I'm going to say your rooms page middleware um editing a room I'm sure there's something else but let's just go ahead and sync this up all right so I think there was another place let me just double check something real quick I think obviously we can clean up any Imports that are gray out go over here and do the same thing okay that looks good great room action I want to make sure this is and clean up and doesn't invoke so something I like adding to my applications is when you create something I like to show a toast I think toast just give that user that extra feedback and we're going to try to add that in so over here there's a toast component with shad CN and this is what it looks like you click it and you'll see a toast pop up I know my screen is hiding it right now but we we'll show it in a second so let's just go ahe and grab this toast component and we're going to import that all right let's go so I'm going to go ahead and grab the toast and we're going to go to layout and let's import the toaster and we just need to use it like this so we just say toast use toast and then somewhere um for example like when you create the room form what we want to do is instead of navigating away we want to show a toast let's just go ahead and say import that here go ahead and Auto Import use toast and what we can do is we can go ahead and show it so I think we can say toast and there might be a way to say what's the message actually let's go look at what they tell us to do so just do this all right and this will be room created your room was successfully created and now that I think about it after you create your room wouldn't it make sense to just join it yeah so I think like we should probably just do some a redirect that go straight to the room uh room which means we're going to have to get the room ID back so like let's get the created room back we'll say room. ID and I think I'll need to go here and like return the newly created room which I'm not sure had to do that in drizzle I don't think we'll get the room back here room is declared but is never read let's look at this when you insert I think we can just go ahead and like return the rooms that were created and edited and hover over this what do we get room list never yeah I'm going to go to drizzle and we're going to figure out how to get the created room so after inserting how do I get the thing that I just inserted um it looks like you can say returning let's try that I'm going to say returning oh sorry I need to do that inside of the actual like method so here I'll say returning and then over here I'll say returning and I think what that'll do is now we'll have the whole room you can insert a row and get back its postgress SQL and SQL light such as this you can't do that in my SQL yeah I mean this should have given us why is this not working hold on great room while [Music] returning I do this what is inserted inserted is an array I might just do that just return the first thing that was inserted and then what does this give us same thing so I'll just return updated there's probably a quicker way to kind of do that um like do they have like a first or something I don't know so now go back to the action this should be defined it is and so we can say return the room and we could redirect in the action itself but again we want to like have a toast pop up before we just like redirect the user so I'm going to go ahead and just like not redirect in the action I'm going to do it in the front end and now I think this should work so let's let's try this out go to our app let's go to create room I don't even know why I wasn't signed in all right so click create room let's just go ahead and type in a bunch of random stuff click submit and we should a see a toast pop up which we do at the very bottom okay down there here's the toast and then that'll go away and then we are in the room right here so we can just go ahead and leave that room if you want to same thing with editing a room I think editing a room we should get some type of user feedback going so edit room action I think I can just go ahead and add that here now I think we do redirect inside the edit room action so we'll see if this is going to cause issues or not it might be fine um let's just go ahead and edit this room I'll click on the edit and I'll say this is a test go and submit it and it did it says room was created although we we don't want it to say room was created I'll say room updated your room was successfully updated so pretty easy to do um now one thing I'll I noticed is that header as you zoom out like the coloring here is like not going full screen so we should probably fix that goad and go to the header let's try to figure that out so this whole header component here we have container on it I don't think we want the container on this we need the container on probably this one go and add it there and see if that fixes our issue there we go looks like that's full screened but unfortunately that doesn't look too correct either oh I think the issue is like notice the whole page it's not contained either so we should probably zoom out and then we're going to find the layout and inside of the children we definitely want this whole thing to be in containers and we should do that that go ahead and paste that in there now that's contained so if you zoom out you're on a 4k monitor like everything will be centered which is probably a little bit better all right let's just keep adding features so another thing that's very important to have in your applications is the ability for users to delete their accounts um usually gdpr laws require that a user can delete their accounts and all the data associated with their accounts so let's try to add that to the header let's go and find um where do I do that so like somewhere we have like an avatar count drop down here it is and then we can just go ahead and right next to sign out we're going to add a menu separator drop down menu separator let's add a separator and then we're going to add a delete button so delete count like this and let's see how this looks like add a delete icon here all right delete account maybe there's a better icon for that but that's what we're going to use I don't see a separator though is the separator not showing up go back and see drop down find [Music] separator yeah I'm not seeing the separator but I don't know it's probably fine so same thing with deleting an account we shouldn't just go ahead and delete the whole account when they click this button we probably want to show a dialogue so let's find that alert dialogue which we did in another component over here and we could basically take this whole thing and we could just paste it I believe right here for delete icon now I've had issues with like nesting certain items in other places um so we'll see if this actually allows us to do this I'm going to try to put this whole thing here and I'll put that there and then obviously import some of the stuff all right let us see if this works I'm going to click on my thing click delete account and it closes out yeah so this is a an issue I have seen where like I'm nesting an alert inside of like a drop down here and then the drop down gets autoc closed which means that this thing gets deleted so instead let me copy this whole thing out go back to what it was and we'll keep delete account there um but what we want to do is I'm going to P put it on the outside of that entire drop down menu so that if it closes it doesn't like hide the alert I need to reimport all that stuff because I deleted it on accident and the way the and so the alert dialogue it has a um an open right so we can just go ahead and like say open and open change we can just go ahead and say const open and we're going to just kind of pass through these things it gives us more control we have fine control over like this this thing if we wanted to and what we could do is when you click this we're just going to go ahead and um open the dialogue so I think down here on the item itself we'll say onclick set open true okay menu item must be used within menu all right I'm getting a weird error um I don't know what I messed up but one debugging technique I would give you is you start getting weird errors comment out everything that you think might be causing the error so it's obviously related to something here this alert dialogue stuff uh I believe because I have drop down menu item here instead change it to a uh we don't even need the trigger that's what we don't need just delete the whole trigger and we'll just use the alert as is and let's try this so now if I click delete account this pops up are you absolutely sure this action cannot be undone this will permanently remove the room and any data associated with it let's change the copy a little bit this will say this will permanently remove your account in any data you uh have how about that and so if you click yes delete my account that's when we need to just blow away everything so I'm going to go ahead and just make an action called delete account action like this um one thing I'll show you that you can actually just have server actions def find like lit literally right here like you could have a function that gets invoked I think you could just say use server in it if you wanted to instead of having an actions directory or file you can kind of do it this way um I like just having a separate actions file because I think it makes things a little bit easier so I'm going to say actions. TS the only downfall is you have now a th files that say actions TS everywhere so that's kind of a pain um but we'll say use server and then I'll say export async function delete count and we'll have to do something so first of all let's go ahead and bring in that delete account action and add that suffix there and then we're going to invoke it from the front end when they click on that yes delete my account and then when it's done we're going to close the alert all I'm kind of just assuming it's going to work perfectly fine so how do you delete a user's account um really you just have to get their session so how do we get the session in other places we just did this let's just go ahead and get their session like that go ahead and grab that if we're not logged in you must be logged in to delete your account and then finally we could just go ahead and say like add a method here inside a data access called users. TS now I'm going to say export async fun function delete user and then we're going to have a user ID here a string and then we need to bring in uh what do we need to bring in let's just go ahead and bring in everything how about that and then DB we could say delete and then we're going to say user which I don't think we have oh here it is users and then we'll say where go ahead and let AI kind of do that for us What fields do we have on that go to the schema real quick and let's look on users that should be the top level thing and we have an ID okay so yeah this should work we should be able to delete that why is this complaining though type string is not a parameter of SQL wrapper delete users where E equals oh okay it's it's going to be users. ID so again we have um if you go back to the schema we have on delete Cascade on everything so if you delete the user that should also delete their account their sessions their tokens and it should also delete their rooms hopefully and we also have this testing thing we don't need that anymore we can get rid of that all right so let's call this so I'm going to say await delete user and then we'll pass it the session. user ID actually I guess it's called session user. ID here and then finally we probably want to redirect the user back to the homepage because we should log them out as well now how do we log them out I don't know how we can log them out now I don't think we can call sign out from a server action so this maybe I won't redirect here I'll just do this logic and if everything works fine we'll go back to the method like technically this could be async we could wait on this and we could say router. push and go to the homepage um but ultimately we need to say sign out and make sure we call that and I think signing out will just um actually we can just give it a call back Ur like this we don't need to do R do push and technically setting this to be open false like I don't think we even need to do um we'll keep it in just in case actually no I don't think we need to do this let's just go ahead and do those two actions and that should sign us out and redirect us so I'm going to go to like my rooms over here and then I have two rooms attached to this user so if I were to go and just delete my account click yes it signed me out go to drizzle refresh I have no rooms anymore it deleted my user um this is my other account so that worked perfectly fine awesome sign back in we can just remake that account as well now something a lot of applications have is like blank placeholder state so right now there are no rooms in my system and it might be nice to have like an image that says there's no rooms so I like using something called undraw um undraw doco you go there and we can just find like a an icon like not found or something and let's just find an icon that seems like it might be a good approach to like no data here we go this might be good we're going to download this SVG and put it in our directory okay and then let's go back to the page uh which was browse so let's go to the browse page and we want to display if there's absolutely no rooms then we should probably display that okay so I'm going to go down here and say if rooms. length is equal to0 and we're going to display an image actually I'll make it a div make it a div inside the div we'll say image source is equal to slash um no data SVG the width is 200 height is 200 alt is no data image something like that and then underneath that we could say just put like an H to no rooms yet great one but you can create one you can create one how about that you know never mind I'll just call I'll just say no rooms yet um and then here we'll say class name is flex I'll say justify Center item Center and let's go back to our app let's make sure this shows up gos no rooms cred yet we definitely want to do a flex column on that so we'll say Flex call the Gap of four took a while to reload the H2 itself we should probably say class name is text of 2 XL sa that and then we could just go ahead and like put some Argin top 24 on that thing just to move it down and we'll do the same thing with your room so so like we should probably copy and paste this we'll go to um where's your rooms we'll go to your rooms and then we're going to go over here paste this in again we'll Auto Import this maybe change the text to say you have no rooms and then sometimes I like to add a button underneath this so like it just lets the user quickly do the action they need to do when something's not there so like they can just cck to create room can also create it up here if they want to go back to browse there you have it might make sense to do the same thing with the other one so like uh let's find that button put it down there just so that there's two different ways the user can get reminded to create the thing so I think we have implemented quite a lot in this application I do want to point out one more thing that stream does provide a chat SDK so we could actually have some live chat functionality added in if we wanted to bring that in they have some good docs that kind of explain how you can do this and of course they have integration with react so you can kind of go through here you are able to bring in a chat widget which that might be the next steps if I were to continue doing that is like add a chat widget here so users can chat with each other upload images maybe upload code Snippets etc for right now I want to show you how you can potentially get this deployed to production so so I'm logged into Railway which again is a paid service so there's various ways you can deploy a nextjs application you can use verell you can use SST you can maybe just host it on netlify but you're going to need a database and you're going to need a host to basically host your nextjs application I've been using Railway for my little site projects I think it's pretty good um this is not sponsored by Railway I'm just saying that this is a service you could potentially use um but it will probably cost money right to set up an account it cost like $5 and they give you $5 credit so anyway I'm going to click add a service and we're going to create a database now locally we're using postrest so we probably want to use postgress as well and that'll spin up a postgress SQL database for you second thing we're going to do is I'm going to add another service and I'm going to hook it up to our Dev finder repo so now we have a database is spinning up and we have a host to run our service or nextjs service somewhere now as postgress is getting set up what I'm going to do is I'm going to grab some of these variables so for example there should be a postgress y let's try to find that here it is you look at here here's the URL I'm going to copy this and we want to make sure that we run our initial migration to set up the taes so remember the way we did it locally is we said DB push but we can actually change that and connect it to a remote database if we want to so instead of doing drizzle kit DB push and using this config file we're going to change the database URL so I'm going to say mpm run DB push and inside of ourv this is like a hacky way you could do it um overall like you'd probably want to have this set up in your cicd pipeline let's grab that database URL variable again okay I'm going to paste it in and now this will basically overwrite our local one so if I save this and I run DB push we should see it apply those changes um if I scroll down down here I say yes execute all these commands it's going to create all those tables go back to railway go to our data no notice that we have the rooms the accounts the sessions Etc so that's how you can do like a quick migration deployment from your local machine super easy to do now secondly we need to make sure that we set up our deploying devinder service with some environment variables so the thing I like about railway is that it actually looked at ourv file our sample and it knows that we need to add some stuff in already so like for example I can just go ahead and put that database URL here the Google client ID we could to go ahead and grab that the secret let's grab that next off secret I'm just going to grab this one grab this API key and then we're also going to grab the secret stream key now obviously some of this stuff when you're going to production you need to change right you should not be using this you need to actually generate a real secure next off secret and for the Google client ID and the secret you probably shouldn't be using the same IDs and secrets that you're using for your Dev environment for your production environment so you want to go in you want to create a completely different Google uh app with different credentials and probably turn that on for production let's just go ahead and say add all and there should be a way to basically redeploy this after adding um your environment variables so I'm going to click here apply nine changes I'll say deploy and that should kick off basically all of the stuff that I've been running locally it's going to run it on a remote server and we should get a deployed app so if I look at this you can see it's going to start building and then it's going to end up deploying and it's going to ask us if we want to add in a custom domain now while that's deploying let's go to settings and I'm going to say generate a domain you can also hook in a real custom domain which I'm not going to do in this instance but now we have a domain here which we could potentially use now we do want to go back to our devinder oo client IDs and we have to basically make sure we add in that new URL that Railway is given us or else when you try to log in it's just not going to work so I'm going to say API off call back Google go ahead and save both of those and now when this fully gets deployed we should be able to access it on a deployed URL all right so now it says that our app is active and we should be able to go to our app here this will take a little bit of time to propagate but then once it's ready you will see our application hopefully deployed here all right and so it's loading up notice that this is the application that we were running locally but now it's working on a deployed environment so let's verify we can log in and do all the other stuff that we're doing before hopefully it works I'll sign in sign with Google um there is a little thing that's messed up here so when I click log in notice that took me to Local Host 3,000 that's not good we actually need to make sure we set a next off URL and that's kind of outlined in the next off documentation so I think we can go back to railway and we're going to go to the variables here and make sure we add in a new variable and we're going to say add in the full URL for our app here so let's just do um do this add that in go ahead and just redeploy that change and just for the sake of it we should probably have that local so like let's grab the next off URL we're going to say HTTP Local Host 3000 and then in the sample we should add it in here probably all right so that second deployment is done let's go here and just hard refresh just in case by signing in one more time okay so now if I log in should kick us back to our production URL and if I go browse rooms there should no longer be any rooms here so let's just go ahead and create another one I'll say Dev finder and working on a side project I'll put the URL there and I'll say typescript nextjs and submit let's make sure that this can create the room um I don't know why I took it back to the homepage it's probably something we have to fix but good enough let's just go ahead and look at the room here and now we can join it let's say allow the microphone and allow the camera and everything else should probably just work like it did uh locally and then we can go back to your rooms and we should be able to edit this one like we did before and click edit add an exclamation mark that works fine and then we should be able to delete the room awesome and then also oh I think we're missing some like I don't have the delete Account button so I need to delete the account I need to um do a push we also don't have the placeholder stuff there so I think I have a bunch of changes locally which I probably need to make sure I get at added in I'm going go ahead and say ability to delete account and then placeholder or empty State images and uh and that should automatically kick off another Railway deployment and we should see that in about 5 minutes I think that is going to wrap up everything I'm going to cover in this tutorial again the code can be found at github.com webdev cdev finder it'll be in the description link below and then of course I do want to give that final special thanks to our sponsor stream go check out getstream.io and play around with their libraries if you ever need to get a really easy to implement video or audio or chat share components and react as you saw in this video is very easy to get integrated so I definitely recommend and like always I have a Discord Channel you guys are welcome to join if you have any questions about this tutorial or want to ask me anything the link for the Discord will be below in the description other than that have a good day and happy coding