SaaS Notion Clone with Realtime cursors, Nextjs 13, Stripe, Drizzle ORM, Tailwind, Supabase, Sockets

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
finally the video you've all been waiting for so far you have learned how to design this beautiful website completely from scratch in figma but today we're going to be converting this beautiful design into a full stack production ready build so let's go ahead and see what you're going to learn in this one single video we are going to be using NEX js13 with react drizzle omm Shaden UI superbase Tailwind socket.io stripe superbas presence and superbas real time to build this applic first we will convert our design into a fully working landing page our entire application will also give the user the option to choose between dark mode and light mode we will create a full authentication system with login sign up two-factor email confirmation with a custom email template all with superbase when the user first signs up they are prompted to create a workspace to get started our application will have restricted features for pro and free plan members only Pro Plan members can have have custom logos have more than two collaborators for a workspace and have more than three folders for a workspace on the top of the sideb bar free plan members can see how much of their free plan they have consumed our application is going to be a combination of workspaces folders and files and workspaces can be private shared or collaborating creating folders or files instantly gives the user feedback by adding them to the sidebar with no delay as we know free plan members can only have three folders so once they exceeded the limit of their free plan they are prompted to upgrade to access Pro features even though we are using server side data we can make changes across the entire application client side in real time for example if I change this title here it changes everywhere yes I know amazing the user can also change the icon for the directory from multiple places in the application to any emoji that they feel best resembles it again it happens in real time across the entire application you can add Banners To Each directory by simply uploading an image like this and the banner instantly shows up on the page you can also update and remove the banner as you like deleting a folder or a file first moves it to the trash instead of deleting it permanently this way users collaborating in the directory can still work on it even if someone has deleted it users can then restore this file or even delete it permanently if they wish to users can change their workspace settings add and remove collaborators change their profile information and update billing settings by clicking on the settings icon collaborating users on a specific directory are shown at the top right corner with their profile picture and this is made possible with superbase presence making changes to a document will debounce the changes and save them to the database to improve performance indicated in the saving status badge at the top right corner however real-time changes are broadcasted to all us users almost instantly and here is something that has never been done on YouTube before we have implemented realtime cursors to show what collaborators are doing within a document even cooler if a collaborator makes a selection the selection also reflects on all collaborators working on this document the cursor also has name tags that pop up if you hover over it with a random color to uniquely identify each collaborator create folders and files are also in real time which means all collaborators will have data that is perfectly in sync collaborators are also notified when directories are moved to trash but can continue to work on them like we spoke and can restore and delete them for each other our application can also accept monthly subscription payments from users this is done through a portal where they can enter their credit card information users can cancel their subscription and also update their credit card information in a customized portal that is synced with stripe and superbase with the products and services you sell even better our application is completely responsive including mobile and desktop to provide a seamless experience to all users we believe in action-driven content so we have placed challenges in this project for you to solve if for some reason you choose not to do these challenges the answers are in the Discord in the description below that's right we believe that taking action is the only way for you to to actually learn watch and develop at the same time and that's why we built this whole series which is action-driven content with that in mind this is a beginner friendly video so if you have no idea what is web development or what a production ready build would look like this is the opportunity for you to learn I hope you're excited because there's a lot of new value that you're going to learn in this one single video so let's jump straight right into it before we start guys I want you to get your laptop and do this with me because we are going to start developing in this whole application together okay so the first thing we want to do is let's create a folder for our project and let's call it web prodigies Das Cypress just like this okay and once you're done with that you want to drag it and drop it into your Visual Studio code and that's just going to open up your folder for you next open up your terminal by hitting command J and type in npx create-- apppp at latest space period okay and guess just go ahead and hit enter and that's going to give you some prompts here so hit yes for typescript for ES lint hit yes for Tailwind CSS hit yes for Source directory hit yes for app router yes um no for this one and that's going to um go ahead and spin that up now we're going to install drizzle orm drizzle orm is a tool that allows you to communicate with your database uh create schemas and do a bunch of stuff it's kind of like Prisma uh or mongoose if you worked with these tools before okay so let's go ahead and type npmi uh drizzle Das o and we also need postgress for this we also need EnV okay so go ahead and hit enter and let those packages install next type npmi drizzle dkit and save this as a Dev dependency create a EnV file in here just like this and let's go into ourg ignore and also ignore that file so we can just put it anywhere in here EnV just like this okay and um guys I really recommend you have my repository open when you're developing to just so that you can copy paste some things okay because we're going to use this EnV example file to copy our environment variables and um we're going to populate these with the database links and you know so on so forth so go ahead and copy that and paste it in here so if you haven't already go ahead and create an account with superbase and head over to the dashboard and all you have to do here is just click on new project and rename this to web prodigies Das Cypress just like this and go ahead and generate a password and copy this password guys don't don't like forget about this because once this page goes away you're not going to be able to see this password again okay you can reset it later and I'll show you how to do that but just copy it come in here and just paste it right in here and then click on create new project now this page will show you the Anon key and a bunch of stuff so let's go ahead and copy that Anon key and paste it right here the service R you want to reveal it copy that as well and paste it right here this is your uh public superbase URL okay so copy this and paste that URL right here guys sometimes this page kind of disappears and if it disappears all you have to do is go to Project settings click on database and you'll find all the values in there okay now to set up drizzle orm let's create a file here called drizzle. is where to find um the migration folder and so on so I'm just going to type in import from drizzle kit just like this and we want to import type config just like this and uh we also want the EnV package that we just installed so do this EnV like this and then we're going to config ourv right here so we're going to say config and we're going to pass in path and set Tov just like this if um there's no process. EnV do um database URL and if it's not there we're just going to console.log cannot find database um URL right after that we're going to export default create an object here and say schema do/ SRC SL lib slabas schema. typescript we're going to create this in a second guys okay so just to solve this typescript problem let's just say satisfies config just like this so now you can get that typescript stuff and then let's say output and we're going to set this to/ migrations we're going to build this folder too driver to use which is going to be PG in our case and we want the DB credentials which is going to be an object with the connection string set to process. env. database l or we're just going to set an empty string right here make sure you also verify guys please verify if the variable names are correct okay so make sure you verify this um because this is going to cause a lot of unnecessary issues head over to your root directory and create a new folder migrations just quick heads up in the next video we will be building the best application on YouTube yep that's right because the next application is going to be built by you we are going to be be using the comment section to determine what features to have in the next project so go ahead and comment below what feature do you want to have on your project and we will make it happen so don't forget to subscribe to get notified when that awesome video comes out and please drop a like on this video to support your boy so that I can provide more free value just like this this and inside that you want to create a schema. typescript file this is where you're going to have your migrated schema files stored in here you want to also say export and just do an object for now I'll tell you why later and um inside our source directory we want to create a lib folder just like this and then create a superbase folder right inside that inside the superbase we want to say db. typescript and then create another file in here schema. typescript and in this schema. typescript you can export this as well for now okay and in our database what you want to do is first you want to import drizzle from drizzle o/ postgress JS just like this postgress from postgress like this import Star as. EnV from EnV and then import Star as schema from and here I'm actually going to use the migrations folder migrations schema just like this and now let's config ourv file so env. config like this say path set it Tov awesome let's say process. env. database URL once again just confirm that there is no there are no spelling mistakes here and if that's the case we're just going to console.log no database URL to create our client here so we're going to say clients equal postgress invoke it and pass in process let's take this right here copy paste right in here and um we're going to set this as string so we don't get that typescript error and then we want to put um an object as a second parameter and set it to Max set to one create this drizzle client right here so say drizzle and pass in your client and pass in this schema okay and let's also export default um this uh DB file so this allows us to query our database and things like that but we also want to migrate this stuff right after this we want to say const migrate DB is equal to async function first we want to say console.log migrating client await migrate which comes from drizzle orm post crjs migrator okay so invoke that and pass in your new database uh client that you just created and pass in an object here and say migration folders and you want a migration folder migrations folder and then set that to migrations so we're going to wrap this in a TR catch bring it up here and then we're going to actually let's change this to an orange color successfully migrated awesome and in here we're just going to console.log or we can we can just paste this in here and put a red emoji and just say um error migrating client and now we need to invoke our migrate DB so basically what's going to happen here guys is every time our DB is being U used it's also going to fire this migrate which is going to keep our schemas up to date with the database so the next thing we're going to do is we're going to create a bunch of custom scripts okay that's going to basically help us run our migration files so go to the GitHub repository click on the repo and you want to go to package.json which is right here and you just want to copy this these scripts right here the pull command will basically pull all the new changes from the database and update our local schema files the generate command will generate the migrations the drop command is used to drop any of the migrations that we don't want to push and uh the check basically helps us to you know keep everything up to date with our local schema files and since we put the migration file inside our database itself we actually don't need this so I'm going to go ahead and remove this migration script right here and now we're just going to create our um our tables for our projects go to the schema file inside the superbase folder and what you want to do is say export const workspaces equal to PG table just like this and that comes from PG core and then you want to say workspaces and then create an object here so everything in here is going to be the column for our database okay uh for our table sorry so we want to say uu ID this also comes from PG core inside this you want to put the name of the column in the database okay this is what we're going to use locally in our file and this is what we're going to use in the database okay and you want to set this to default um default random invoke that and you want to set the primary key invoke that too and you want to say not null so this is very similar to just SQL syntax uh created at and uh set it to timestamp which comes from PG core guys not MySQL core invoke it and say created uncore at just like this with time zone we're going to set it to true and we're going to set the mode to string just like this workspace owner which is going to be uuid workspace owner to not null this will reference something guys we'll come to the references in just a second which is title which is going to be text and this comes from the same PG core invoke it and we're going to call this title in here and set it to not null just like this awesome and then we're going to have an icon ID and we're going to set this to a text icon ID not null 2 just like this and then we want data which is going to be text set to data and this can be null so that's fine and then in trash this is going to be set to text again and this is going to have um inore trash as a name in our um in our table logo which is going to be text logo Banner URL Banner URL just like this okay so make sure you have done this do all of this with me guys this is the best way for you to learn if none of this makes sense it's okay you're going to eventually understand because this is called pattern recognition so um go ahead and do this so let's see if everything is working perfectly it may not if it does we will find um the bug and we will we will solve the problem go into our source into our app file go into our layout. J s and you want to just import DB so just type DB and hit enter okay that should bring it from superbase DB there looks like there is some sort of an error that took place let's go ahead and see what is the problem and let's fix that problem all right guys so the error basically all I did was I just console. logged the database here and um it says that it cannot find the meta journal. Json file and the reason is because we did not actually um create a migration script so let's run npm run generate so I see a bunch of errors here what is this error it says transform failed um let's see okay es5 so this is another thing we need to change so head over to your typescript config and change this to es6 here and let's run that command one more time awesome guys so now if you go to your migrations folder you're going to see a SQL file right here with the migrated script if you do npm run Dev if everything went well you should not see any errors in here there we go so we just refreshed it and it says successfully migrated now if you go to your database and if you click on tables you will see your table right in here if you come into any sort of Errors just head over to the Discord in the description and everyone in the community is going to help each other out so the next one we want to create is called folders so let's say export cons folders equal to PG table just like this and set it to folders like this and give it all the columns actually we don't even have to type this we can copy this exactly from here paste it in here we just don't need the workspace owner and then we need the workspace um so workspace ID which is going to be a uu ID like this and we're going to call it workspace ID in the database and this one is going to be set to references and this takes a call back which is workspace bases do ID and we also want to mention on delete Cascade so that we don't have any data just floating in there so const export files equal to PG table and set it to this and now we want to copy everything in here paste it in here but we also need another relationship which is the folder ID which is a uu ID just like this set to folder uncore ID which references folders. ID okay awesome and also we need to set the on delete so on delete to Cascade just like this go ahead and close this by hitting contrl C right just close this command or you can even shut it down and what we want to do is run npm run generate to generate our migration script run npm run Dev go to the browser make sure it Els are refreshed like this and give it a second successfully migrated awesome so now to create our profiles for our users we're going to call it a users table but I want to show you guys something really cool that superbase gives you straight out of the box okay if you head over to SQL editor and you click on quick starts you will see a bunch of templates you can literally just copy from so we're going to go ahead and click on the stripe subscriptions which also gives us access to the users table right here don't worry guys I'm going to explain everything in detail what this does and everything about it uh but let's go ahead and just um create this just going to make a couple changes to this right here guys so just go ahead and follow up with me you'll be fine okay so the first thing we want to do is say email in here and you want to set that to a text okay and um in our Ro level policies we see that only the user can view their own data but we want to use this um as like a user management system so that everyone can see each other's data so we're going to change this to true for updates so only the US user can update their own information so we want that to be here so we're going to say everyone can view um user data like this on users okay and um let's make sure we also have the other stuff in here um updated at U we could probably have that maybe um we can set that to updated uncore at um which is going to be a timestamp with time zone right here guys we are basically creating a function trigger okay what this trigger does is when a new user is signed up with our application this trigger gets invoked we're going to add um a new property so that we can also add the email to um the user okay so all you want to do here is at the end you want to say comma email I keep saving it I'm so used to it guys um email right here and after this uh Avatar URL you want to say new do email just like this we're going to focus on all the role level security stuff later that's not super important right now okay we just got to get the application set up and make sure we get all the logic um correct and then you can set all the RO level security stuff and what this Ro level security means just for someone who doesn't know what it means is basically it's sort of like restricting who can access who can view delete and update data in that specific table so that's why it's called Ro level security that way if our front forgot to do some Logic the backend will restrict the uh user action because of that road level security so you see how powerful this is guys superbase just went ahead and built everything related to um our subscriptions for stripe and all that kind of stuff so we don't even have to do anything just going to show you what's happening here basically we're creating some products here with some properties right so it's a table called products and uh we have some Ro level security on that too and then we also have some um some enums here one time and reoccurring payments and the payment interval right here and then we're creating another table called prices in here which can hold the prices of our products and um we're creating again some Ro level security this is just basically um some columns right in the table and then we're creating um a subscription type which is active trailing we're just going to use active but this is already done for them by them so we'll just keep it and then we have another table called subscriptions which is going to keep track of who is subscribed and um you know are they actually subscribed when we can get that through the status subscription status okay and then we also have some Ro level security on it extend this right here and go ahead and hit run so it says we detected some potential destructive operation I think it should be fine you can go ahead and just hit execute query okay so it says invalid let's see what is the issue so I think I found the issue it's because we didn't put a comma right here so let's go ahead and run this one more time and execute the query awesome guys so it went ahead and built out our tables so let's go to our tables now and you will see everything in here and we also see the files the folders and the the workspaces in here so the next step is how do you sync changes that are made from superbase into your local schema file well that's pretty easy all you have to do is run npm run pull this is why we have those custom scripts so let's hit npm run pull and there you go it pulled everything for us so now when we go into our schema file um you can see right here that all the new tables the files the folders um the customers everything's been populated so you're going to see an error here um it comes from time zone and we're actually going to fix that just in a second so we're going to change this entire Default Time Zone thing so let's highlight this right here and highlight it everywhere else so you can do that by hitting command D so what you're going to replace that is uh that withth is basically default invoke it and say SQL now that's it I tried to import the time stamp guys but um for some reason it just wouldn't work I don't know the time zone I mean it just wouldn't work with Drizzle but this is how you can kind of solve this problem and the issue is every time you pull now you're going to have this problem but hey you just got to change it right that's just how it is but anyway all right so we got to do a couple more things okay the first thing we need to do is uh copy the subscriptions from the migrations folder the migration schema go into your own schema file and paste it in here and the reason is because because that subscription um it's going to keep you know updating every time you pull from your database and that's going to cause some problems so um let's just copy this and paste it in here so that we can change it every single time that error happens okay so make sure you import these from the right tables um and the the right module so let's see here we have only PG core okay awesome and the next thing guys I made a very stupid mistake here I really really apologize for this but it's good that we came across this error because now I can show you how to fix something if you make a spelling error okay so we're going to select icon ID everywhere in our application and we're going to change it to Icon ID just like this okay I haven't noticed any more spelling errors but if I have made anything else I really suggest you go into the um the GitHub repository and copy and paste these things because you're not going to you know it doesn't really matter all this stuff doesn't really matter now that we did that all we have to do is say npm run generate and hit enter and that's going to create another migration file for us right here and now if we close this and do npm run Dev refresh the browser um hopefully we see a success awesome a successful message if we go into the browser now let's expand this refresh it and if we go into let's just say workspaces and search for Icon ID okay awesome it's updated here if we do npm run pull it's going to pull the new data and if we go into our schema of course we're going to have that error and that's why we copied that and now you can see in our workspaces or folders um icon ID it's updated awesome guys so let's go into our schema I know this is a little Annoying it is really annoying for me too I don't know why um why they don't have that in there but I'm just going to copy this go in here and I'm going to replace the subscriptions table with this new data right in here now let's move on to building our op a so I'm just going to shrink all these folders here I'm going to open the source and the app directory and um in this page file I'm going to delete all the code after main also remove the class names right here so let's go ahead and remove that and we're just going to say homepage just like this okay and now the next thing you want to do is go into your app directory and then go into your global. um CSS and you see this body tag remove this and we want to go to the top of our file and we're going to say HTML comma body and say height and we're going to set it to 100% just like this okay and now if you set background color to Black for example you'll see it's 100% of the height now you want to go to your app directory and we're going to create a folder called um o like this okay o and then we're going to create another folder in here and we're going to call this Main and then we're going to to create one more and this is going to be called the site this will not be included in the routes this is just sugar coded syntax it's just easier to uh group everything with similar logic we're going to use Shaden UI and Shaden UI allows you to build beautiful components and it uses radic UI behind the scenes so we're going to use this library to help build our application so I'm going to open my terminal and I'm going to come to Shad CN UI and I'm going to copy this right here and just paste it um in here and we're going to hit enter and that's going to go ahead and spin up shsi and UI for our project so it says would you like to use typescript we're going to say yes and we're going to use default guys you can use New York if you want to but I suggest to use default and uh we're going to use the Slate right here where is your global. CSS file SRC slapp SLG global. CSS okay and hit enter would you like to use CSS variables for colors yes and um where is your Tailwind config file it's in the root so we're just going to leave this as is and then config import we're just going to hit enter enter again are you using react server components yes we are for this right configuration to components. Json we're just going to hit Y and that's going to go ahead and build all our dependencies out let's take a look and make sure that everything was done correctly so we see the components file inside our source directory we see a lib folder it has a utils folder and this utils is basically um part of Shaden UI all right guys I just want to point out an error that took place so when we were creating our Shaden Global CSS file basically I think I put a space before that and as a result it actually created a different file for us so what we're going to do in here is there was some stuff at the bottom here so we're going to just going to copy that stuff that comes from um This Global CSS we're just going to delete this folder right here we're going to go into to our Global CSS and at the bottom we're just going to paste that if you guys are here from the previous video you know that we built the entire design for this beautiful application in figma so we are going to now copy our colors into our application so that you can use them if you'd like to go into your UI system right here and you want to go to the plugins and there is a plugin called figma Tailwind CSS you want to run that plugin so let's give it a second awesome and now it's going to show you all the colors in your application okay you can rename these to whatever you'd like I just want to show you how to use this so that you can convert your colors but um we are actually going to use chatsi and ui's Library itself because they already have a theme that is very similar to us so why not use their theme right so all you all you got to do if you want to use these colors just scroll to the bottom and hit next right here and this will give you um your font base size I want you to select 16 pixels and now you want to hit next again and um this you can just leave it as is and then hit next one more time and that's it guys it's going to give you all the colors that you need all right to create themes we're going to go to shatzi and ui's documentation and you want to click on theming sorry dark mode right here and then click on nextjs and now you want to copy this one okay the install next themes and you want to open your terminal and paste that right in there and hit enter okay this is going to go ahead and spin up themes for us so now when you head over to your Tailwind config file you're going to see a bunch of uh colors put in here okay so I'm going to show you how to also use the colors from our figma just in a second go to your figma file and copy the colors from here like this and scroll to the bottom right after the card and you can just simply paste it in here now you have your theme setup with with the colors that work for dark mode and light mode and also your custom colors from figma now we need to create our theme provider so that we can use this next themes that we just installed so head over to your library folder your lib folder and you want to hit um command M to create a new folder and we're going to call this providers oops it's all capital providers just like this and in here we're going to create another file called Next theme uh provider okay. TSX just like like this use client so let's import Star as react from react and then let's import theme provider like this from next themes but we're going to call this um as next themes provider just like this and then we're going to import the type theme provider props from nextjs them's um disc types and then we're going to export function theme provider and in here we're going to have the children and we're going to have all the props sorry props like this now let's provide the types for this so we're going to say theme provider props just like this and now we're going to return the next theme provider just like this and we're going to put all the children in here and we also need to pass in our props right so let's say props like this um right into this component awesome now all we need to do is go to our app directory layout. J uh TSX and in here we're basically going to wrap all our children in this new theme provider okay so go in here and just say theme uh Provider from lib Libs like this and invoke this and bring the children right up here so we also need to pass in some properties in here so we're going to say attribute is set to class um default theme is going to be set to dark because we want to work with dark mode as default and then we're going to say enable um system okay so it uses this the system color as well now to get the Shad CN theme itself you want to click on the themes here and we are actually going to use this Violet theme so click that and you want to click on copy code it's going to give you this stuff right here so go ahead and copy everything from here and replace all the the code that you have here um with this new stuff so we're going to update a couple of these colors I'm going to do that and you don't have to do this guys you can just go to the GitHub repo and just go ahead and copy everything from here you don't have to build it okay um but we'll go across it in depth don't worry about it but just go ahead and copy this one from here and just paste it right in here and that's about it guys that's how we set up themes for our application all right so now we're going to go ahead and build our landing page so the first thing is we don't need this page anymore so we're actually just going to go ahead and delete this from here awesome so that should go away we're going to see an error but that's okay guys I'll show you how to fix that in just a second we need to go into this site folder right in here and we need to create the following so first go ahead and create a layout. TSX and you want to also create a page. TSX rafc and you just say uh maybe homepage like this yeah so the layout also you want to say RF C and let's change this to uh let's just call this layout okay home page layout like this the homepage layout is rendered when we go to the root file and that's where we're going to build our website here so we're going to say section we're going to create a div like this and we're going to set this to class name overflow hidden padding X is four we're going to say on from small devices the padding X is going to be six margin top is going to be 10 from small devices we're going to set it to flex and then we're going to say from small devices we're going to set it to flex Das column like this and then we're going to say Gap D4 and then we're going to say MD justify Center like this MD items Center like this okay and inside this guys we're going to create another component and this is basically going to be our title section so if you see in our figma file we have this section right here so we're going to just build out this title section so that we can reuse it for all the um other sections in our landing page as well so go to your components right in here which is under components we're going to create a folder in here and we're going to call this uh landing page okay like this and inside that we're going to create a title section. TSX we're going to say title section just like this let's also create the props for this so interface um title section props sorry guys props like this and we're going to say title is going to be a string sub heading is optional which is also going to be a string and we're going to have a pill right here which is also going to be a string and let's use that here react. functional component title section C props and let's extract it from here title like this then we need the subheading which is right here and then we need the pill from here and what we're going to do in here let me just close this so you guys can see clearly turn a uh react. fragment okay just like this and inside this we're going to create a section class name of flex flex-all gap of four so justify Dash Center then items start MD which is from The Medium devices items Center just like this okay awesome and inside this section we're going to have an article like this set it to class and this is going to be um rounded okay of full like this or let's save this let's go back here again we're going to say padding is going to be like one pixel and then text SM dark BG DG gradient-2 WR dark from- brand- primary blue like this see this is how we can use our custom colors to dark um 2 Dash brand and we're going to use primary purple from here awesome and now let's go into this article and we're going to create a div right here sorry guys a div like this we're going to set class name and we're going to set this to rounded of full PX D3 py to one we're going to say dark BG Das black and inside this we're going to pass in the pill right after this article guys right below it we're going to say subheading so if any subheading was provided then we're going to return something else we're going to return something else so in this block we can just use a react fragment like this and we can say we can say H2 like this and we can give this a class name of text- left text- 3XL from small devices we want it to be text- 5xl and then from uh small devices again we want the max width to be 750 pixels MD so from medium devices we want it to be text Center and font D semi bold and now inside the H2 we're going to put the subheading U sorry inside the HD we're going to put the title and then we're going to create a uh our subheading right in here which is going to be a paragraph tag dark text- washed dasp purple and we're going to set it to 700 and then we're going to say SM max-width d450 pixels text - Center and let's put our subheading in here and if there is no subheading provided then we're going to return something else which is H1 like this class name set to text- left text- 4XL SM so from small devices the text is going to be 6 XL SM from small devices again the max width will be 80050 pixels and then we're going to say MD text- Center we're going to say font D semi bolt we can just provide the title like this awesome and now we can actually use this component to um show what we needed to okay so in here let's say title section like this and in here we want to say the pill should be equal to let's put an emoji there maybe we'll use this Star Emoji and we'll say your workspace perfected which the title prop which is going to be platform just like this okay right in here so our layout. TSX is not actually giving us the children components so we need to do that we'll set this to children are going to be react do react node like this um actually we're not going to return this anymore we're going to return a main and we're going to say um children just like this so now when this grows you you see our title section can be reused for every single device so back in our page. TSX let's do the following so let's create a div and I'm also going to hide this so you guys can see we're going to say class name we're going to say BG DH padding is going to be two pixels and then margin top is going to be six rounded is going to be- XL BG Das gradient to R from Das primary to das brand Dash primary blue like this and um we're also going to say from small devices we want this to have a width 300 pixels button like this variant BTN secondary class name is going to be width Das full and now we want to say rounded -10 pixels padding -6 text -2 XL and BG Dash uh background okay so you see that right there awesome so we're going to say get Cypress free okay so the rounded here didn't work because of this error so let's go ahead and say rounded Das XL let's say margin top of six I think this is this is better after this div so right after the button guys there's the div here so hit enter from there and create another div we're going to say class name from medium devices margin top is going to be negative uh 90 pixels okay we're going to hit enter here I'm sorry about this this is m MD not mg and then we need to say from small devices we want the width to be full we want the width by default to be 750 pixels and then we want flexx justify center items Center and then margin top is going to be -40 pixels relative SM ml so margin left of 0er pixels and we're going to say margin left of um negative 50 pixels like this inside this we're going to create an image which comes from next image just like this and we're going to say SRC we're going to provide a source for it and we're going to say alt and this is going to be called application Banner so you want to go to the GitHub repo go to public and you want to get the app Banner right here so click on the app Banner and just right click and download this drag this app Banner in here import Banner from um this is public slapp banner.png just like this and now we can take this banner and we can put the banner in here and now let's refresh the page and now you can see this Banner right here next we want to create this fading effect on the image so if you look in here you see we have this fading um kind of um you know look to the image so let's go ahead and do that so to do that all we're going to do is say div right here and say class name equal to bottom d0 top- 50% dg- gradient-2 D2 DT sorry dark from Das background left- Z then we're going to say right- Z here absolute and then we're going to say Z10 now you see we have that beautiful gradient right at the bottom it's kind of like a fading effect so so I'm just going to go ahead and Shrink this div here so we can create more and uh what we're going to do is we're going to create another div like this and we're going to give it a class name of relative okay and this is going to be the second part what we're going to have here is basically these client logos so go ahead and download all of these and move it into your public folder so what we can do right here is I want to change some stuff right here because this is actually not a section this is the main tag so our layout is wrapped with the main tag so what we're going to do is we're going to select this section right here and now we're going to just return a react fragments I don't want to pollute the um the jsx in any way and now instead of these being divs these can be section and this one can be a section as well now this makes uh this has more semantic meaning than what we had before go into this section and we want to create a div here and say class name and say overflow hidden hit enter and I'm just going to do Flex here and after we're going to set this to content like this within empty string after we want to say dark from dbrand Dash let's see do we have dark yep we have brand Das dark and then we want to say after is to- transparent after Das from D background CK background like this and then we want to say after BG DG gradient-2 left after right- Z after bottom d0 after width Dash 20 after is going to be z-10 just copy this right here and we could just paste it in here so change all these Afters to before and then before BG gradient to instead of left to right um so bottom zero like this and we can do the same here change this to after and then after this bottom instead of right here we want to have left actually let's do this absolute and we want to do the same for this one so after after absolute okay so I'm going to go to the GitHub repository going to go into Cypress I really recommend you do this too cuz it's going to save you so much time and you're going to copy this clients right here and we're going to create a file in our Libs and we're going to call this constants do typescript okay and just paste that in here and you want to do the same thing for this too which is a users this is basically our our testimonial card guys copy the import statements from here go to the top and just paste that right in here so what we're going to do here is we're going to say dot dot dot array of two elements and we're going to say map invoke this and then we're going to get a call back function here so since we returning this we're going to just return a div for now key we'll we'll give it something in a second not going to work but we'll give it in a second and what we want to do here is this is going to be the array right so the key we're just going to to say array like this one we're going to give it some class name Flex flex no wrap animate slide which we will create in just a second right in between this we're going to get the clients c l i n clients from our library constants map want to return a div in here again key equal to client. alt the class name relative width is going to be 200 pixels margin is going to be 20 shrink to uh zero Flex items to Center and inside this div we're just going to return an image like this and put Source equal to client. logo and the alt is going to be client. alt and the width is going to be 200 and the class name is going to be object Das contain a Max with of none all right also one more thing we made a tiny error here what we did is we put the entire array in here yep so we want to take that out and put it right before this one we'll fix this in a second just remove that comma from there awesome there we go but you can see this gradient effect in the side right this is what we just created with um all of this stuff right here so head over to your global. CSS file we're going to create an animate slide right here so we're going to say animate dslide and we're going to say animation 15 seconds slide linear infinite we also have to create those key frames here so we'll just say key frames like this and we'll give it the name which is slide um and in here we're going to say from transform Translate x0 and two like this we're going to say transform translate X to 100% so if you refresh the page and you look at the logos they're going to just keep scrolling like this and when they come to the end it will loop around so now right after this section guys right here we're going to say we're going to create another section and let's give it some styling so so we're going to say a px so padding X4 let's do that and we'll from the small devices we want the padding to become uh six pixels or I mean six Flex justify center items Center Flex Das column let's go ahead and create a div and give it some styling in here too so the width is going to be 30% blur of 120 pixels rounded full h- 32 absolute BG um background is going to be brand let's see what colors we have here um we actually want primary purple but we're going to say uh by 50 and then we're going to set the Z to A -10 if you don't know what this is guys I'm going to show you in just a second okay so it's this Purple Gradient which is basically this thing right here U right right outside this the title section just like this and provide the title which is going to say um the following so I'm just going to copy paste this you can of your meetings all in one place so we're going to say pill is equal to Features just like this so we have to type div here and set the class name to margin top of 10 Max width is going to be 450 pixels justify center items Center relative and then from small devices the margin left is going to be zero rounded sorry guys let me do that one more time rounded - 2XL and then border -8 border Das washed actually 300 not 800 border opacity set to 10 we're going to say image in here like this the source we're going to get in a second the alt is going to be another banner and um class name is going to be rounded das2 Excel so go to our public folder right here so it's this calendar right here okay go ahead and just download this calendar we're actually just this is just for it looks guys just to just to make it look um a little better and let's import this calendar so from Banner we're going to change this to Cal and we're going to import Cal just like this and now you can copy this go to the bottom here and in your image tag you can Source you can just paste this calendar right here and if you refresh it there you go how amazing is that guys so after this section go ahead create another one and say class name relative like this okay I think this is the one so I'm just going to copy this and I'm going to replace this but I'm going to change the width to full like this so now we have one more right there um okay let's change this to 50 six so this div is just going to be open and inside this we're going to create our title section like this with the title which I'm going to copy from uh here the following you can go ahead and just copy this guys don't go don't don't start typing it out it's going to take a lot of time so I see something wrong with this and I'm going to fix this I think because it's on top of it oh okay my bad so this is actually supposed to be after this div so we have it like this okay and we need to create sort of a container so let's also replace this with a closed tag and um this container is going to have the following classes okay which is margin top of 20 just like this padding X is going to be four from small devices padding X is going to be six we're going to have Flex Flex D column overflow x hidden overflow visible okay just like this and now inside this one we're going to pass our title section just like this and let's delete that awesome there you go and now we need to create those cards these cards right here but before that go back to the public folder and you want to download this Avatar folder right here and drag them into your public folder under a folder um called avatars so let's go ahead and render out this section which is basically going to be um an array of uh two because we need to have two sections of these so array dot um array at two just create like this and we're not going to do the same mistake we did before so we're going to do dot map after that return a call back function here and uh we're going to say array index we're going to get access to both of these and for now we're just going to return a div the key and I'm just going to use random U uu ID for now um right here awesome and this is also Al going to have a class name and here guys we're going to use Tailwind merge so we're going to say Tailwind merge like this and in here we're also going to use clsx and we're going to invoke that and in here we're going to provide margin top of 10 Flex flex no wrap gap of six and then let's create an object here and we want to say Flex row reverse and we're going to say index equal to 1 animate like this animate Dash slide uncore 250 seconds linear underscore infinity and then we want to set this to true so let's copy this paste it here but here it's going to be underscore reverse and it's only going to be reversed if the index is equal to margin left 100 view width ones where index is equal to 1 and right after this put a comma here and you want to say hover paused okay so let's say users which is going to come from lib constants do map like this we're going to have we're going to pass in a we get access to this call back right here we're going to say testimonial and the index we're going to create another component called custom card and this is not here right now so we're going to go ahead and build that components into your landing page components and just say custom card. TSX ra fce custom card component and let's come back here and let's import this we're going to say key testimonial. name in our custom card we're going to use Shaden to create a card for us a card and we want this so let's copy this npm let's let's open this let's exit out of this let's paste this in here can use type here for now card props equal to react. component um props like this and um this is going to be a type of for the card so card is going to come from here say type custom card props equal to card props and the following card header react. react node then we're going to have a bunch right here so I'm going to call this content footer and let's go ahead and say react. functional component and we're going to pass in our custom card props in here and let's go ahead and extract class name card header the card content card footer like this and then everything else we're just going to do dot dot dot props like this and in here we're going to remove this and we're going to say card this and in here we're going to say class name equal to CN and we can import that as well and in here we're going to say width is going to be 380 pixels pass in our class name like this pass in the props into this card components here we want to also bring in our card header like this from UI card make sure it is UI card and not something else pass in the card header and then let's import card content and then footer like this Gap four like this run npm run Dev awesome there you go you can already see something is happening our cards are showing up but of course it looks absolutely horrifying right now but don't worry about it we're going to fix it in just a second go back to your component right here we're going to pass these props into this guys and we're getting that from users okay so if you don't know what users are it's basically this array of OB objects that has a name and the message okay for each of the card class name width is going to be 500 pixels shrink zero rounded XEL dark BG - gradient but this is going to be to top then we also want to have dark from Dash border dark to background there you go you see it's creating that cool effect and now let's go ahead and pass in the other properties which is the card header which is going to be a div like this we'll pass in class we'll say F items Center Gap 4 and inside this div guys we're going to use the Avatar so first we need an avatar and a bunch of stuff so go to shaten UI scroll to the bottom where till you find Avatar and we're going to click on this Avatar and open this and we want to paste right here and hit enter so let's go ahead and do npm run Dev just run that and let's bring that back so in here we're going to have a div and we just did that right there so we need to provide the Avatar now which make sure you don't select radics guys this is why I kept looking at that so components okay components slui that one and then you want to say Avatar image and this is going to have a source and this source is actually going to be a dynamic string so slash um avatars slash dollar sign index + one and um at the end we just want to put PNG okay and then we want to have Avatar fallback from components UI and in here all we're going to do is we're we're just going to pass an AV or something like this okay so we see some errors here guys um I'll go ahead and fix this just give me one second okay so you see I made an the same issue that I told you guys not to do which is to not import anything from radx UI and from Shad CN only so go ahead remove that and just paste it in here so once this Avatar is done we want to create another div here and inside this you want to say card title like this put something in here so what we're going to say is testimonial. name and we're going to give this a class name with text foreground then we want to say card description and this class name is going to be dark text- washed purple 800 inside this card description we're going to pass our testimonial. name do2 lowercase after that we want to go to this card so right here we we had card headers so I'm just going to shrink this and now we want to have card content a paragraph with a class name set to dark text- washed purple 800 inside this paragraph we're just going to say testimonial. message like this there you have it guys look how beautiful that looks so right after this section go ahead and create another one for our pricing cards give it a class name of mt-20 PX D4 SM PX is going to be six and inside this one we want to say title section so I'm just going to copy this title section right here into the bottom right here and the text for this guys is just going to be this so you can go ahead and just copy this from the GitHub repo uh just save yourself some time we're going to say div create a class name and we're going to say Flex Flex Das column reverse from small devices we want it to be Flex row we want the Gap to be four justify to be Center on small devices we want items to be centered oh sorry items to be stretch items to be Center and margin top to be 10 just like this and inside this div go ahead and open this and say pricing Cs and we're going to import this from um our our GitHub repositories so what this basically has guys is just an array of objects okay and the array has um the plan type the pricing description whatever and then the features which is an array which we're just going to render across pricing cards. map and in this function we get access to the card and we're just going to return a custom card like this and we're going to say class name equal to clsx and invoke this like this and and here we're going to say width is going to be 300 pixels rounded to XL dark BG Das black sl95 backdrop blur D3 XL relative and after this inside um this part right here we're going to put an object like this and also this needs a key so let's let's just do that right now card um dot plan type like this and now in here we want to say border Das brand- primary purple primary purple uh 70 this is going to be true when the card. plan type is equal to this is going to be pricing plans like this okay you can go ahead go back into our constant file and we can just copy the rest of these might as well right so copy this go to our constants file right here and all the way at the bottom just paste that right there import it so we're going to say dot um Pro Plan awesome so when it's a Pro Plan it's going to be of that type cool now we have our card set up let's set the properties for it as well card header equal to and we need to say card title like this okay and this is going to basically have the following um styling on it so text 3xo font Das semi bold and inside this title we want to pass in a bunch of stuff so card dopl type equal to we're going to say pricing plans. Pro Plan and what we're going to return is basically a react fragment and inside this react fragment we're going to have a div so it's going to have hidden by default dark set to block the width is going to be full blur of 120 pixels this is very similar to what we created before guys if you remember a full height of 32 actually let's do this so you can see more here and then um absolute like this and then we're going to set the BG to be brand primary purple we're going to take 80 of that negative Z of -10 and then we're going to say top Z right here and just close this tag here and let's say image like this and say source is equal to a diamond which we're going to get in just a second and the alt is going to be Pro Plan icon like that okay and the class name is going to be absolute top-6 right- 6 so let's go ahead and get this image so the diamond again comes from our Cypress public folder so let's go ahead and grab that real quick quick all right guys so I just created I just dragged those two check and Diamond inside an icons folder inside the app inside the public and uh let's go ahead and use that okay so let's go back to our code let's go ahead and just duplicate this in public we're going to say SL icons like this slash diamond. SVG and we're going to call this diamond just like this right after this you want to say card. plan type so so it says Pro Plan and free plan looks amazing right cool and now after this part right here you want to say uh card footer is equal to an unordered list and this is going to have small tag inside it and this is going to have the following styling so font is going to be normal and then we're going to set this to flex and then margin bottom of two flex-all Gap D4 just just like this okay awesome and then inside the small tag card. highlight features let's just see what that does okay so it just shows the highlighted feature right there right below this sorry we want to say card. features. map so we get access to the feature here and what we're going to return is actually a list item right here key and that key is going to be equal to feature just like this class name Flex items Center Gap D2 awesome and inside this list item go ahead and just create an image so we don't need this actually we'll just say image like this and set it to Source equal to and we're going to get the check icon which I also copied from the file uh from the GitHub repository set this one to check icon right here we'll change this to check icon and let's get the check.svg right from here after this guys inside the list okay after the image just say feature like this this is actually the card footer so let's say card content say card content like this and then we'll say class name is P0 and in here we're going to have span tag class name equal to font dormal and then we want to say text d-2 XL and inside this span you want to say card. price after the span you want to basically say plus card. price greater than Z if so then we want to do something if not we want to do something else well we're going to return another Span in here just like this with a class name sorry this is price guys right here and the class name set to dark text- washed Das purple D800 like this and then um we will'll also give it a margin left of one okay and inside this we want to have some text here so we're just going to say slmo like this so there you go it says that price with that with that right there after this just say p and say class name dark text- washed Das purple and we want 800 from this and in here we're going to say card. description yeah let's put a dollar sign right here okay looks so much better because of that row reverse we show the Pro Plan first and then we show the free plan and finally we also need to put a button right after this so that you know they can click on that button class name wides space no wrap width is full and margin top is four just like this okay and inside this guys we're going to say card. plan type if it's equal to pricing plans dopr plan well we're going to say go pro like this and in here we're going to say get started just like that um we also need to provide a variant so the variant here is going to be button primary awesome guys so it looks sort of similar to this right it looks great maybe you can maybe we can change the background of this card so let's see what's wrong with that so maybe we can change this to 60 40 Yep this looks better guys so you can set it to 40 and that kind of has a better glow effect behind it so the next thing we're going to do is set up authentication for our application from scratch so what we need to do is we want to copy this uh command and we're going to execute this Command right in here okay so we're going to open our terminal and um I'm going to go ahead and also shut down the server like this and say npm I at superbase SL a-h helpers - nextjs and then add superbas SL superbase I think it's .js yeah superbase DJs actually all right and go ahead and hit enter and let that install all right everything looks great so let's go into our Au folder under the app directory so Source app and a and we want to create a login route right here login and inside that a page. TSX and in here I'm using rafc which is basically uh react Snippets um so we're going to say login page just like this and now we're going to create the entire um system or the entire page for this login route okay so how we're going to do this first is by saying const router equal to use router and this has to come from next navigation guys and this is going to be a client component okay use clients up top just like this and um now the next thing is we need to say const submit error and set submit error equal to use State import that and it's going to be an empty string in the beginning so to create our form we're going to need some helpers from U from the shat UI Library so you're going to scroll here in chat and UI under components you're going to go to form right here and um where is that right here and then you're going to scroll down to where it has the npm command copy that that and paste that in here now if you go to your package.json you will also see um a couple um new packages that are added to our project which is react hook forms and also I think um yep hook forms right here and now we're going to import Star SZ from Zod cons form equal to use form we're going to invoke this and we're going to say z. infer like this type of form schema which we're going to create in just a second okay but uh right before that we're going to come in here and we're going to say mode we're going to set this to on change and now we want to import Zod resolver resolver from Hook forms SL Zod just like this awesome so it's saying something here oh Z resolver okay and we want to go down here and say resolver equal to um Zod resolver invoke it and then we're going to say form schema again we're going to come to this just give me one second and then we're going to say default values is going to be set to email which is going to be an empty string and password to an empty string as well okay so this form schema where are we going to create well we're going to actually create some types here so let's shrink this open our source file and in our uh Libs file we can have um inside this we can basically create a new file and say types. typescript so we're going to say export const form schema equal to Z that comes from Zod doob invoke that and we want to say email z. string you need to invoke that and we're going to say describe set that to email with the capital maybe we can say oh yeah it already has an email on it and then we'll put a message here which is invalid email and the next one is password which is going to be z. string again and we're going to describe this as password uh with a capital P and then we're going to say minimum of one password is required and we can import this form schema from our file there you go so that's the power of this form schema okay and now we're also going to need some is loading state so uh is loading actually comes from the form itself so we're going to say form. form state DOT is submitting so we're going to say um on submit is submit Handler which comes from react hook forms z. infer just like this and this is going to be type of form schema set this equal to function just like this and that's going to have the form data as a parameter and we're going to get back to this in a second let's go ahead and build this form right here npm run Dev let's refresh this if we go to the login page like this we will see the login page right here awesome this is exactly what we want form which comes from um the form which comes from components UI form okay so let's use this and um in here we want to pass in everything from the new form form that we just created so let's create another form here in this we're going to have an onsubmit and we're going to set that to form. handle submit and put in our onsubmit function right in here we're also going to give this a class name of with full justify center from small devices we want the width to be 400 pixels space- y-6 Flex Flex Das column like this and in here we're going to say on change and we're going to say if submit error then we're just going to say set submit error to an empty string okay and um in here we're going to now create the link which comes from next link like this and we're going to set its hre to be equal to um just a backs slash like this and we're going to say class name with full Flex justify left items Center just just like this image which comes from next image we're going to say source which will come to any second the alt is going to be the Cypress logo with a width of 50 and a height of 50 just like this okay and what you want to do is click on the Cypress logo.svg download this image right here logo okay from dot do slash do do slash and um you want to go into the the public directory SL Cypress logo.svg put the logo in there and let's go and see what that looks like awesome so you see when you click it it goes back to the homepage okay cool and now you want to basically create a span in here and say um Cypress just like this font semi bold dark text white and then text for Exel ml so margin left of two Okay so like this so let's go to our layout. TSX file and we're going to basically import a new uh font from here guys and that's what we're going to use throughout our entire application so we're going to import from next font SL gooogle like this and the font we use in our figma file is DM Sans so let's get DM Sans right here you want to say dmore sand like this and this can stay as is awesome and just go ahead and refresh it guys and that will update the font to the newer font now come to the class name here and we wanted uh we want to use Tailwind merge and we're going to basically say BG background and we're going to set the enter class name right in here now let's go back to our um to our file now after the link down here I'm going to say form description and I'm going to basically give this a class name of text - foreground sl60 and all platform you can also copy paste this stuff guys we're just doing it right here but uh no problem you can copy paste it okay and then we're going to use the form field form item form control inputs and this is not here right now so you're going to see an error so let's go to Shad CN UI and install that input field awesome guys that's done and now let's go back to our code and let's import this input from components UI inputs and now we need to provide these props for this one okay so what we're going to do here is we're going to say disabled is equal to um equal to is loading so the loading that we got from the form itself so that when we are setting the API request we block the form right form. control like this and then we want to say name this name is going to be the email field render something in here um a call back function that gives us access to this field like this now whatever we put in here guys you want to just go ahead and copy this and replace this and paste it in here for the form inputs we need to also provide its properties so let's say type equal email like this placeholder is equal to email okay and finally we need to do dot do do field so we need to use a spread operator and put everything in here also this is not needed so we can just close this right here and then let's refresh our browser awesome so now the next thing we're going to do is we're going to create a template file that we can use for our authentication system okay so let's go in here to the a right here this a directory and we're going to create a file and this file is going to be called template. TSX okay and we we can use RAF CE and we're going to change this to template okay just like this awesome say interface template props and we're going to say children is react. react node here we're going to say react. FC and we're going to pass in our template props in here and now we can extract children from here awesome and what we're going to return here is basically um we can return this div but it's going to have a class name and the class name is height is going to be screen the uh p is going to so padding is going to be six Flex justify Center in here we want to remove this template and we want to have the children in here so now you see this template will be used everywhere for our login page and our uh sign up page as well so after this form control right here guys right before this form item and in between this we want to have the form message and let's create the other form field right now so I'm just going to go ahead and copy this form field paste it down here I'm going to change the email to password like this and change this one to password right here form item like this here to the placeholder is going to be password and you can also see that in the browser awesome so it says password and it changes cool so right after this form field right below it you want to basically have a submit error which will come to in a second form message okay like this and we're we going to pass in the submit error in here okay and this submit error is actually um for when after we submit it and if we get any response from the database okay so let's go down here and we're going to use the button guys and type equal submit class name with full and padding six and inside this we're also going to have a loading spinner or some text okay so let's set the size equal to large set disabled is equal to is is loading like this okay now you want to go into your components folder we're going to create this and say loader. TSX and then you can do rafc this is just an SVG file that I found online that makes it really easy to use loading um to create a loading spinner I didn't want to download a whole install a whole library for it but you can just go into the components file and you can copy and paste that so right here I'm just going to go ahead and copy the return from here and just paste that right in in here if is loading so if it's not set to true then we want to return login or if not we want to return the loader that we just created after this button guys you want to create a span right here and say class name self contained so we're going to say don't have an account a link like this href set to slash signup which we'll also build in a second and then we want to have the class name set to text- primary and inside this link we're going to say sign up so the next thing we're going to do is some sort of setup uh some modifications to our Global buttons so for our default button let's go ahead and remove whatever's in here and let's just set that to um Whit space it's not going to give us any intelligence that's really bad but uh widespace no wrap like this and then BG D primary and then text- LG text- primary - foreground say shadow -2 XL and this Shadow is actually going to be a color shadow okay so it's going to be Shadow Das Indigo D600 divided by 50 and then we're going to say border -2 hover we're going to set that to border D foreground rounded is going to be set to LG so actually don't like this border here so I'm just going to remove that border so yeah that looks so much better also guys if you don't want to type all this stuff you can go ahead and just copy it from the GitHub repo but I just want to show you so you know what's actually happening in the code okay so right after this one we're going to create two more variants and the first one is called BTN primary this is slightly different from our original primary and it's going to basically have um the following properties okay so white space is is going to be no wrap hover is going to be set to text primary foreground just like this and then we need um dark is going to be set to um BG gradient to top and for dark we're going to have it from Dash and you can put this uh in here which is dollar sign two sorry hasht 242 3 2 C like this and then we want to have dark which is going to be two dash like this and we're going to say hashtag um we're going to create this hex code right here which is he hch I'm sorry F18 just like this and then finally dark text- primary D foreground like this border and then hover border sorry border is going to be primary dark and we're going to set this one to border Dash another hex code 464 553 like this and then we're going to say um dark hover BG Das accent and then hover BG Das primary like this and then dark hover like this we're going to say border Das muted Das foreground like this okay and then text will be large and uh we're going to also make the font normal I think yeah this is good let's create one more and this one is going to be called BTN Das BTN D secondary like this and this is going to come in handy when we're creating a landing page okay but for now just follow through with me and I'll show you what it looks like later so widespace will be set to no wrap dark is text- primary um- foreground I forgot a k there and then text will be LG and then font will be normal okay just like this awesome the next step is you want to go in here into your uh folder right here and inside the lib folder you want to create another folder in here called server actions inside that we're going to create um o actions just like this. typescript okay first we have to say use server up top and then we need to export async function called action login user this is basically going to give us the email and password just like this this is going to infer something so we're going to say Z do so first let's import C from Zod do infer type of form schema from our types and now this will resolve itself so we're going to import create route Handler client from superbase Au helpers nextjs and now we're going to say cons superbase equal to create route Handler clients and we need cookies in here guys then we need to say const response is equal to await superbase doo. signin with password invoke that and we want to pass in the email and the password just like this turn response uh return the response just like this so now in our um login page right our page. TSX we're going to do the following so we're going to first uh extract this error that comes from await login user invoke that and we're going to pass in the form data like this and we're going to await this if error exists form. reset set set submit um submit oh set oh I made a mistake here did I Su yep I made made a mistake here so let's go in here and let's change all instances of this to submit error like this awesome so set that to error do message and finally if there is no error we're going to say router. replace and replace it with dashboard just like this which we're going to come to in just a second so once we're done creating this you will see this error and the reason is because this server action is still in beta all you have to do is scroll to your next config and you want to provide experimental which is an object here and you want to say server actions and set it the true and let's say npm run Dev and let's spin this up and this should actually fix our problem awesome guys now you can see everything works as expected all right guys next we're going to build the navigation for our landing page so let's go ahead open this right here I'm just going to shrink this real quick open source go to components and in here we have the landing page we're going to create header. TSX and we're going to use RAF CE and change header just like this okay and in this header right up top here so const routes equal to an array and then this is going to be an array of objects with the title prop set to something and then um the next property is the href which is going to be set to another string okay so in the title for the first one we're going to have features and this href is going to be hashtag features just like this okay and all we're going to do is copy this right here and we're going to paste it as a second element and we're going to do that a bunch of times okay the second one is going to be resources like this and go ahead and change this to resour resources like this and then this is going to be pricing and this is going to be pricing as well and testimonials testimonials like this okay this is extra so we'll just go ahead and delete that so we're also going to create a const here called components equal to an object with the title set to string the hre set to a string two and then sorry this is not going to be equal this is going to be like this and this is going to be an array of this right here and let's go ahead and update this now we want to have description set to an array of these values right here okay and so let's create the array here and I'm just going to go ahead and copy this guys you can copy this from um the GitHub repository I'm just going to paste it here to save you a lot of time awesome and now for the header in here what we're going to do is first say const path set path equal to UST State like this and this is going to be string so what we're going to set this to is Hash products just like this and in here we're going to return the entire header so let's change this here to header like this and give it a class name of P4 Flex justify Center items Center and in here we're going to have an image tag right here which comes from next image we're going to put that right inside this okay and going to have a container which is the link tag which again comes from the next link like this and we're going to say href is going to be this backs slash right here and now we can move this image inside this link okay and SRC equal to logo which we're going to get in a second like like this alt is going to say um Cypress logo we're going to have the width set to 25 and the height set to 25 awesome and then finally we're going to create a span with the class name of font set to semi bold and then dark is going to be text- white and in here we're going to say Cypress dot okay so we're creating this but we also need to render this out right so we need to see what we're doing so first let's go ahead and import this logo right at right up top just like this public Cypress logo we need to go ahead and render this header component so let's go into app layout. TSX sorry the layout. TSX under the site and in here we're basically going to create header from components Landing just like this awesome cool so let's go ahead and see what's the issue so this needs to be a client component because we used state in there so let's say use client up top and that should fix our problem um okay it also says that it cannot find this logo here so we're going to do this manually which is do do SLU SL Cypress logo just like this now you can see it up here so let's go ahead and fix all these The Styling now okay so on this link tag you want to give it a class name and set the width to full justify left items Center and now that will be on the left side also let's give this Flex right here okay so that goes side by side and maybe we'll give it a gap of two okay perfect all right now let's move to the next section so now we're going to create navigation menu right here okay and this actually comes from Shad zenui so let's go ahead and install these components so head over to Shaden UI scroll to the bottom and click on navigation menu and then click on on this npm Command right here and we're going to close this and paste this right here okay so let that go ahead and install the components for us awesome now we're going to go here and copy this from here and we're just going to paste it up top okay just like that so we're importing all the elements that we need and now we can go ahead and build our header so the navigation menu is going to have a class name of hidden MD set to block just like this and then um inside this navigation menu we're going to have navigation menu list just like this this is going to have a class name of Gap set to six like this navigation menu item okay like this and this menu item is going to have a navigation menu trigger inside this like this and this is going to have an onclick put it right in here we're just going to say set set path to hasht um resources like this okay basically guys this we're kind of setting it to the ID of the element okay and that way you can navigate to if you want to after the on click we want to have class name and we're going to set that equal to CN import that invoke it and we're going to pass an object right in here and we're going to say dark text- white and this is going to be just like this we're going to say path equal to resources like this okay and the next one is dark text- white um 40 and this is when the path is not equal to the ID resources just like this okay font here is going to be normal like this set this to true and then text is going to be extra large and set this to true as well okay awesome and right at the bottom here guys in between the trigger we're going to put resources just like this so let's see what this looks like for that we have to run npm run Dev and re uh refresh the browser so now guys when you extend the screen you will see the nav bar show up and then when you shrink this it disappears okay so let's go ahead and build the other sections as well so right after this trigger you want to say navigation menu content like this and this is going to have an unordered list and it's going to have a class name of grid and then it's going to have Gap three padding six medium devices the width is going to be set to 400 pixels uh on large devices the width is going to be set to 500 pixels on large devices the grid is going to be call Dash um sorry called grid calls Dash like this and we're going to say 75f frore 1fr okay just like this and now we want to create a list item in here and give it the class name of row dpan-3 create a span for example and just give it a class name of flex height full width full select none like this and then we're going to give it some additional styling right here which is flex-all justify end rounded DMD BG dasg gradient-2 DB from- muted sl50 this is going to be 2- muted p-6 no- underline like this and then we're going to have outline Das none focus is going to be Shadow Das MD okay and inside this we're just going to say welcome or something okay so let's see what this looks like when you click on this you see it kind of shows um the section right here okay awesome so let's shrink this and continue and after this we're going to create a custom component called list item right here it's not here but we're going to create it in just a second so you want to scroll to the bottom and you want to say const list item equal to react do. forward ref like this react. element ref and you want to pass a in here I want to put a comma react. component props without ref like this and pass in a again right inside this one and then after this you want to invoke this and pass in a callback function and this callback function will give you access to class name title children and everything else is going to be in ins side props okay and uh what we're going to do in here is we're also going to say ref right after this so let's return a list item like this let's go to the bottom here and say list item. display name equal to we're going to say list item just like this okay so this should solve um this weird typescript error and inside this list item we basically want to say navigation menu link just like this and we're going to set as child um as the prop here and this is going to be an a tag um that's going to have a ref set to the ref that's being passed in class name equal to CN and then put a string and say group block select none space- y-1 font D medium leading Das none okay okay and right after this we're also going to expand uh the props into this component okay and in here inside this a tag we're going to have a div and give this a class name of text- white text-- smm font D medium leading dnone in here okay and in here we're basically going to pass in the title and after this div we're going to create a p a paragraph tag and say class name group- hover text- white d70 and then line- clamp 2-2 sorry and then text- smm leading Das snug and finally text- white sl40 okay and inside this paragraph we're just going to go ahead and render out the children that we get in great now let's go back and let's reuse this component up top so inside this list item we want to pass the HF and we're going to set that to hashtag for now and then title will be equal to introduction like this and um this list item inside inside this list item we're going to have reusable components or just copy some string guys okay and I'm just going to go ahead and copy this three times and paste this below each other and they're just going to have some different text in here and some different HR okay awesome and let's go back to the UL so the UL ends here we have the content the item so after this item you want to go ahead and create a navigation trigger like this and inside this you want to say onclick like this and set that to another callback function and this callback function is going to set the path to um the ID pricing okay and inside this we also want to have the class name and this class name is going to be very similar to what we had before guys exactly the same thing but except for one thing we're just going to change the IDS to pricing okay awesome let's go back to this trigger and inside the trigger we want to say pricing just like this all right guys we want to create a navigation menu item so sorry this was an error here and you want to drag this trigger inside this just like this awesome cool so now when we expand this we can see the pricing right there so now when we expand the screen we can see the the resources and the pricing so let's go ahead and complete this component too so after this trigger guys go ahead and say navigation menu content like this and inside this we're going to have an unordered list like this with a class name of grid width of- 400 pixels Gap D3 p-4 on medium we want grid Das r-2 like this and let's um go ahead and um expand this and inside this we want to have a list item again and we're going to say title like this equal to a string after this guys so what I did was I just uh pasted this again right below this and we're going to change this we need a key right here um so let's remove this key from here so after this item guys go ahead and create a navigation menu item again and inside this we want a um a nav a navigation menu content we're going to create we're going to create navigation menu content inside this with a ul and we're going to set the class name to grid width is going to be-400 pixels the Gap is going to be be 3 p is going to be 4 MD W is going to be 500 pixels MD um is going to be set grid Das calls -2 LG is going to be set to width of um sorry not like this like like this LG is going to be set to width of 600 pixels just like this and what we're going to do inside this unordered list is we're going to say components map we're going to map over this and we're going to basically uh provide a callback function here that gives us the component and this is going to return a list item again okay and this list item now will have the key in here so we'll say component component. tile just like this and um the title here is going to be the component. tile and we're going to say href is equal to um component. hre just like this awesome and um inside this list item we're going to say component do um description guys right here great job so far so let's move on to creating the final part of this which is the testimonials now after this menu item you want to go ahead and create um navigation menu item just like this and this is going to um actually no class for this we're just going to have a link right here and this link is going to have href set to an ID so just put a hashtag right here for now and inside this list item we're going to create a navigation um menu uh link just like this and this is going to have a class name and we're going to set this to CN like this invoke it and we're going to say um navigation menu trigger Style just like this okay we're going to invoke this two we're going to put this here and an object right in here and we're going to say dark text- white like this path equal to equal to Hash testimonials okay and then the next one is going to be dark text- white sl40 path is not equal to testimonials okay and then we're going to say font dormal and set it to true and then text- extra large set that to true as well awesome and inside here we're going to say testimonials just like this so now we have have three um navigation items right here okay that's more than enough actually so let's move on to creating our login button and our sign up buttons so right here under navigation menu you want to create a side like this class name set it to flex and we want to give this a width of full gap of two and justify end just like this and inside this aside you want to have a link component so link just like this with an href set to slash um login which we will come to just in a second and inside this we're going to basically set a button and then we want to say variant equal to button secondary just like this and we want to set the class name to p-1 Hidden and SM block like this and inside this let's say login okay so now when you go ahead and expand this you will see the login button right there looks amazing so um right after this link guys we're going to create another Link in here and this link is going to have an href of back slash signup like this again we'll come to this in a second and we're going to use a button here that says sign up just like this very is going to be BTN primary like this and a class name is and we're going to set the class name to whites space- no wrap okay and now you can see here guys we have our beautiful buttons and our navigation all set and ready to go now when you click on this obviously it's not going to work cuz you're going to get an error because these Pages um of course the login has been created but the signup has not been created so let's go ahead and do that right away uh that error is coming up because we have a link inside another link okay so let's just go ahead and remove this from here and that should solve our hydration problem awesome guys let's move on to the next step now next we're going to create the sign up route right here so go into your au and say sign up and inside that say page. TSX and rafc and we'll say sign up just like this okay so first we're just going to create our form scheme so we can just do it right up here no problem so we're going to say cont um sign up form schema equal to Z from Zod doob and we're going to invoke this and we're going to say email should be set to z. string like this invoke that. describe this is just a string email. email like this and the message is going to be inv valid email okay let me shrink this so that you guys can see much more clear and the next one is going to be password which is going to be z. string like this. describe which is going to be a password right here like this and this is also going to have a minimum of six characters and password must be minimum six characters just like this okay awesome and right after this we also want to have the confirm password which is going to be z. string like this dot describe in here which is going to be confirm password and minimum is going to be six password must be let's just copy this right here must be six characters long just like this and now we're going to pass an additional refine method right here and this is going to help us do uh much more advanced validation so let's say data here data. password should be equal to data. confirm password okay and if not we're going to basically say message and we're going to say password don't don't match just like this okay and after this we're going to we also need to provide this path here so the path here is actually going to be um the confirm password so it no knows where to get that from awesome and now let's move on to this signup component right here so in here first we're going to have const router equal to use router that comes from next navig ation and um then we're going to say const search params equal to use search params and I'll show you why we need this here guys um the reason is because superbase will basically reroute us to this page and we can use the help of the params to determine if there is any sort of error okay so let's just do that right here const code exchange error is equal to use memo which comes from react and we're just going to give this call back function with an empty dependency for now and in here we're going to say if there is no search params just return a string okay um let's do that one more time just return a string right here and then we're going to return search params doget we're going to say error uncore bti n and inside this dependency array we're going to pass pass in the search param that it can do it every single time this changes okay and then after this we're also going to create some other states so let's um go up here and say const submit error and set submit error okay equal to use State just like this and this is going to be an empty string for now and then we're going to say const confirmation and set confirmation is equal to use state like this which is also going to be a Boolean so we're just going to set this to false for now okay and um let's go down here right after this code exchange we're going to create some uh confirmation styling some special styling okay so const confirmation and error Styles equal to use use memo and this is again going to give us this right here and we're going to we're going to return clsx right here and we're going to say BG Das primary like this and we're going to create an object here and this object is going to have BG D r-500 / 10 and this is going to be set to code exchange um exchange error so this one right here okay let's copy that and paste that right in here awesome and then we have a couple more so we're going to have border red- 500-50 and we're going to set this to um this I'm sorry not -50 divided by 50 like this and same thing code exchange error and then text red 700 and this is the same thing here okay so now if we go here let's see if we see our signup page okay so of course this needs to be changed to use client because we're using all these um use States all right perfect so I see it right in here and um next thing we need to do is let's go ahead and create our form so we want to say const form equal to use form just like this let's invoke this for now and in here we're going to first import this from react hook forms and then we're going to say z. infer type of sign up form schema just like this and in inside this we're going to pass an object and say mode is going to be on change and resolver is going to actually come from um Zod resolver like this from Hook forms resolver we're going to invoke this and pass in the signup form schema okay and after this the default values is going to be set to email which is an empty string password which is also an empty string and the confirm password which is also going to be an empty string and um let's go right below this and then we're going to create a function here which is the onsubmit so we're just going to say const onsubmit for now and we'll come to this in a second okay so let's go to the bottom let's also create the signup Handler so we're going to say const sign up Handler and we're going to uh basically just set this to an empty Arrow function for now okay so now let's go ahead and change these right here so first form which comes from opponent UI form is going to basically be everything inside the form and in here we're going to have the form right here like this and we're going to say onchange equal to an arrow function that basically checks if if submit error then we're going to set submit error to an empty string just like this okay and then onsubmit is going to be this new function fun that we created here which is going to be form. handlesubmit we're going to invoke that and say onsubmit right here okay and right after this we're going to have some class names for this which is with full SM justify D Center SM DW is going to be set to 400 pixels just uh we also have to add an extra Dash there and then we want to say space- y-6 Flex Flex call like this awesome and now guys if you re if you remember this is basically the same thing um as our previous one right so we're just going to go ahead and copy that and we're just going to do a slight bit of variation okay so let's go to our login form which is right here let's go ahead and copy everything inside our form just like this let's go back to our sign up and let's paste it inside our form okay we're also going to need to in import some stuff so let's go ahead and do that so link comes from next link image comes from next image and then of course we don't have logo for now but we'll come to that in just a second and then we need form description form field and then we need the form item which also comes from um the component SL UI and just go ahead and import all of this guys and make sure you're importing it from at components um UI okay and the form message as well um yeah we'll come to this submit error stuff in just a second and let's go ahead and also import our button from here and this is loading State let's go ahead and pull it right from the form right up here okay so after we save form let's say const is loading is equal to form. form state.is submitting like this okay now we have that variable so that should solve one of the problems and let's go ahead and get this logo and this logo you know where to get it from so let's go up top right here I'm going to say import something like this from dot. SLU SL Cypress logo and we're just going to call this logo like this so one of our errors are solved and the other one is this loader component so let's import that one just like that great job guys and now we need to just change up some stuff so let's go ahead and do that so right after this form description guys we're going to have something in here so we're going to say if no confirmation and and no code exchange error just like this um why is this not showing I'm just going to copy it from here maybe then it would show oh we said const exchange error that's the reason so code code exchange error just like this okay so no code exchange error then we're going to return something so I'm just going to say div for now and then what we're going to do here is we're going to return a react fragment and inside this right here here we're going to return a button like this we're going to give it a type equal to submit class name which is with full p-6 and we also want to set the disabled prop to is loading just like this and in here we want to again see if is loading is not true then we want to do something else we want to do something else so if it's if this is uh true we're going to say create account if not all right and right here we're going to render the loading spinner right here like this and what we're going to do now is we're going to copy these form Fields right here and we're going to paste it right above this button so there you go we have that and we can also remove our login button because we already created our own button right up here and it this is going to say something else of course but let's move to our form Fields first then we'll come to this part okay so for the first form field we have email and then we have password and then we also want to have one more which is for confirm password so right here we're going to set the name here to confirm password just like this and this one type password and this one is going to be confirm password just just like this okay awesome great job and now we have our button at the bottom renders out these um the loader or the text and if there is a submit error we're going to go ahead and show our error on the page and here we're going to change this to um already have have an account like this and we can send the user back to the login page okay and we can say sign or sorry log login just like this so the user can go back to the login page if they want to and they can come back to the sign up page so right above this form we're also going to do one more thing here so we're going to say con confirmation or code exchange error if this exists then we're going to basically return the following okay so we're going to return a fragment and we're going to have an alert inside this guys and we can get this alert from um shaty and U so let's go ahead and do that so head over to Shad CN UI and go to the alert component and copy this component um this npm script right here we're going to close this and we're going to paste this ADD alert right in here awesome and once that is done inside this fragment we're going to say alert which comes from our components and we're going to give it a class name and these these class names are basically going to come from the confirmation and error styling and now inside this alert go ahead and say if no code exchange error and and and so we're going to render something we're going to render mail check which comes from a lucid react just like this and let's give it a class name of h-4 W-4 okay and after this alert uh after this icon we're going to have the alert title actually I want to make sure I imported that all right from the right place great and in here we're simply going to have code exchange error uh put a question mark here and say invalid link or we're going to say something else here which is check your email like this okay after this title go ahead and type alert description like this and in here we're going to remove this and now in our alert description we're going to again say code exchange error or an email confirmation has been sent okay so awesome guys let's go ahead and complete our uh form sign up okay so our onsubmit function right here is going to have a bunch of stuff so the first thing we want to do is set this to an async function and U we also want to provide provide email and password that come from these parameters and this guys right here this is going to be z. infer like this type of only need the form scheme of uh stuff which is the email and password right U because the react hook forms will not fire this onsubmit function if the conditions don't match so we don't really care about that we're just going to use this right here and what we're going to do here is we're going to say const and um in here we're basically going to make our API request okay so let's go ahead and set that up so let's go into our server actions file which is in here into server actions and we're going to go ahead and create our action uh signup okay so we're going to say export async function equal to this sorry oh let's redo this whole part so export an async function action sign up sign up user and this is going to be email and the password okay and um this is basically going to be um z. infer type of form schema just like this and now that typescript error is going to be resolved and we're going to say con superbase equal to create route uh Handler client pass in the cookies before we sign up the user guys we can just do this real quick we can say um const data is equal to a await um super base. from profiles to select star. equal and we're going to say email equal email okay so I know this is we're not using DB here which is from drizzle I just wanted to show you guys how you can also make queries with superbase okay and don't worry from um the next couple um of the queries we will start using the drizzle okay so next we're going to say if the data. length exists so if data. length exists we're going to say return here like this and we're going to return error and we're going to set this to message user already exists and then we're going to pass in the data just like this okay if not we're going to say cons response equal to await super base. o. signup sign up just like this invoke this and in here we're going to pass in the email and password like this and then we also need to pass in this options which will come um right here so options options like this and this is going to be an object with email redirect to guys so what this link is is basically superbase it needs a link to send the um the user from the email to so that it can exchange a code and this code is basically going to be done with the help of some logic we're going to get to that right after this so let's set the email redirect link to http um SL and of course we need to change this later on so I'll change that in a second so Local Host um like this Local Host 3000 SL API SL SL callback all right guys and I'm going to go ahead and change this link too so that it can be dynamic so just give me one second so head over to your EnV file and you see this public site URL we're going to change that and just put put our Local Host um in here okay so now we can use this in our file right here so let's change this to this and we want to go in here remove everything that is right here and we say dollar sign process.env dopu site URL just like this and finally we also have to return this um response guys right here awesome great job so far let's move on to to completing this email redirect tool link now all right so go ahead and open this right here go into app and we're going to create a folder called API okay and inside this API we're going to create another folder called o just like this and inside this Au we're going to create a call back so which is another route here so call back and inside that route. TS okay and inside this guys we're going to basically import a couple of stuff so let's just say create um route Handler client we'll import that and we also want next request from next server and we also want next response from next server just like this and we're going to export async just like this a function get like this and this request is going to come from uh is going to be of type next request just like this and in here we're going to say const request URL equal to new URL and we're going to pass in the request.url right in here and then const code equal request url. search params why is that not showing up oh there we go search pam.get code just like this okay and then if code exists we're going to say const superbase equal to sorry create route Handler client and we want to pass in cookies guys which we need to import from here so let's go ahead and say import cookies from next slhe headers like this and um now this should resolve this problem here and I'm going to say await superbase doo. exchange code for session and we need to pass in the code in here and finally at the bottom we have to return the next response um. redirect and we want to redirect the user to um we're going to create a string literal right here and we're going to say request url. origin and say slash dashboard just like this awesome guys now we kind of have this set up let's see what's happening okay so I see a problem here so let's go ahead and fix this all right so the first thing let's go ahead and change this to sm- with 400 okay and okay there we go that fixed our whole problem so um sorry about that guys I kind of uh made a small spelling error I hope I didn't make anything else anywhere else but feel free to just put it in the comment section if my typing is absolutely trash okay um all right let's move on now all right guys so we're also going to to use this email template to send to our users whenever they sign up on our application so to do that all you have to do is go into authentications and you want to go into email templates and in here um during sign up you see right in here confirm sign up you can enter any sort of HTML you like in here to create that design so I'm just going to go ahead and copy paste the one that I have that you can use um so just go ahead and copy paste this and this will also be in the G GitHub repository all right so I'm just going to go ahead and paste this template that I have here and don't worry guys I'm also going to put this inside the um the GitHub repository so you can copy and paste that as well okay so go ahead and hit save once you're done and this is going to save your template so whenever a user signs up they're going to get this email sent out to them so let's go ahead and give this a shot and let's go ahead and sign in a user so first I just want to hit create account and as we expected we see a bunch of emails here and the cool thing is since we did onchange this is going to change as we type okay so you see at gmail.com so what we're going to do here is we're going to change this to prodigies testing gmail.com all right guys so also let's go ahead and remove this signup Handler right here okay it's not needed anymore let's go ahead and do the steps that we need to um basically create a user okay so in the inside this one here what we're going to do is we're going to say const error and data equal to await actions sign up user and we're going to pass in the email and the password we can just remove this right now we don't need it right now okay so if there is an error we're going to basically set the submit error just like this and say error in here and then uh we're going to set this right here so error. message and then we want to say form. reset because there was an error and then we want to just return out of this if not we want to set confirmation to True okay so that way our confirmation component will show up on the screen so let's go ahead and reset this and we're going to put prodigies testing something like this testing and let's go ahead and create the account so I'm seeing some sort of weird errors here so I'm just going to go ahead and debug this problem okay all right guys so I accidentally used this form field incorrectly so what you want to do here is this is going to be um a call back function we're going to do this but this is going to ex we're going to extract this value field from here okay go ahead and copy this here and we want to do this here and we also have to do this for our login form too okay so let's go ahead and put that right there and let's refresh and if we hit enter now it makes sense but if we change awesome it works perfectly okay so let's also go ahead and do that for our login page so let's go here and change this field to this field here and change this one too anything else nope I think that's about it let's go back now and let's refresh this page and let's uh basically just say prodigies testing gmail.com and create the account awesome it did that and there we go guys it sent me an email confirmation so now when I go to my email and when I click this I see this beautiful template right here and when I click this click to confirm email it takes me to this redirect link which will then send me to the dashboard page awesome this is exactly what we wanted guys but of course this page does not exist so you're going to see this error so let's go ahead and solve this problem so what you want to do is inside this folder you want to go into your app directory and inside the main folder you want to create the following folders okay so first create dashboard so this is going to be a dashboard page layout. TSX page. TSX just like this okay and in here we want to create another a folder but this is going to be a dynamic ID and we're going to say workspace ID just like this okay and inside this workspace we're going to have a bunch of stuff but for now let's just have this like this right here and we want to have rafc inside our layout component and let's change that to layout and inside here we're going to say interface it's just going to be layout props like this with children and pams are going to be any layout is going to be react. functional component like this and we're going to pass in our props we're going to extract the children I'm going to extract the children and we're going to extract the params so first thing we're going to do in here is we're going to say Main and then we're going to say class name equal to and we're going to say Flex overflow hidden and height is going to be screen just like this okay awesome and inside this we're going to render children just like this and now if we refresh this page um we also need need to have an something in the page. TSX so let's say ra fce and let's change this to page export default page like this and same thing in our layout one problem here guys is when I say login you can see that I'm actually able to access the login page even though I am logged in the reason is because we haven't done that logic yet okay but let's first go ahead and complete complete um testing the login page itself and then we'll move on to the next steps okay and in here we're going to go to the login page and we're going to put some credentials and just hit login awesome so it logged me in successfully and redirected me through to the dashboard page now we can go ahead and build out our middleware file okay so head over to your root directory and create a file here and call it middleware do typescript and inside this we're going going to basically do a couple things so first let's do create middleware client like this we need next um request and then we also need to export an async function called middleware next request like this okay and this is a function so let's invoke that uh and let's pass this curly bracket right here we want to say con response equal to next response. next and after this we want to say con superbase is equal to create middleware clients and we need to pass in the request and the response both in here okay and the request comes from here my bad so awesome and let's say equal to right here and then we want to say const data session equal to await superbase do o. get session like this okay and then we're going to check here we're going to say if request. next url. paath name do starts with the slash dashboard so if they're requesting this page we're going to check if they are actually authenticated to access this page so we're going to say if there's no session then we're going to return the user to a different page so we're going to say next response. redirect them to a new URL like this and we're going to redirect them to the login page and we're going to say request.url okay and um right after this we're also going to do some email redirection search param right here so we're going to say const email link error equal to email link is invalid or has expired okay so let's go ahead and copy this to if request. next url. search params .g get error uncore description so we're if we have this in the search pram and we want to say is equal to email link error link error just like this um if it's equal to this and we want to also check if the request. next url. paath name is not equal to sign up okay then we're going to return next response. redirect the user to a new url url right here going to invoke that and say slash sign up question mark error uncore description like this equal to and we're going to say so we're going to use a string um literal like the string template right here and we're going to say dollar sign request.url . search pam.get okay and inside this get we're going to pass in the error error description and then the next one we have to pass in here is request.url like this and finally I want to do one more thing right here if um login signup do includes request.url like this path name right here then we're going to do the following guys so we're going to check if they try to if the request URL was login or sign up like this then we're going to check if the session exist okay and if the session already exists then we're simply just going to return them to next response we're going to do do redirect here and then we're going to say new URL and pass in slash dashboard and request.url like this so if they are trying to access these p pages but they're already logged in and we have a session we're just going to send them to the dashboard page awesome so let's actually return our res response here um like this and now let's see if we can test this all right guys so just to show you what this looks like in action if I paste this link here and try to go to the sign up page but the error description exists in the URL then it's going to say email link is invalid or has expired okay awesome so now we know this works all right let's let's do a quick challenge kind of like an exercise to see how to debug your application when you come across such bugs okay so right here we have our middleware typescript file and we have um a condition here where we're basically checking accessible link or the next URL path name is of type login or sign up we're going to check if the user has already logged in and if they have then we're going to redirect them to the dashboard page right but for some reason if you do npm run Dev and if you re refresh the browser here you're going to notice that these console.log messages are not going to be printed out in the console this clearly means that our file is not being run am I right so can you guess what is happening hopefully you were able to get the answer but if not this is what's happening so basically we have our middleware typescript file outside our entire project in the root folder right and when you're using the source directory unfortunately you can't do that you have to move the middleware typescript file into the source folder so when I do this and hit move you will notice that I see the console.log and it redirected me to a different page so I just wanted to give you guys a different uh like kind of like an exercise to think because this whole video is going to be with a bunch of challenges where you actually think and take action okay awesome all right everyone the first thing we want to work on is the dashboard page so what we're going to use this dashboard route for is basically when the user tries to access this or they're being redirected from the login page uh or the signup page basically we're going to check if they already have a workspace and if they do have a workspace we're going to Route them to that first workspace that we find right if they don't have a workspace then we're going to allow them to create a workspace right in here so you can do that by opening your folders right here um go into app and inside your main inside dashboard you have page. TSX and and in here we're going to do the following so first let's change all of this and call it um dashboard like this dashboard uh page like this first we're going to say const superbase superbase is equal to create server component client and this needs access to cookies so I'm just going to put um these up top here I'm going to say import cookies from next slash header next SL headers just like this awesome and let's pass in the cookies right in here now um also guys just to give you a quick idea if you go to the GitHub repository everything is written out for you and we also have comments that explain why we're doing the following stuff so if you ever have any confusion the GitHub repository is going to be your best friend okay if you need further explanation the Discord is going to be in the description go ahead and access that and help each other out if you have any questions we'll be more than happy to help you okay awesome so let's go back to what we're doing here so after we create the super base uh what we're going to do here is we're going to fetch for the user we're going to get the user here so we're going to say const um data and this will return a user like this is equal to await superbase do.get um get user like this let's invoke that and this has to be an async function right here and this will give us access to the user okay and we're going to check if there's no user then we simply want to return okay and also our middleware is going to handle this stuff so we don't have to worry about it so we're just going to return here and then we're going to say const workspace equal to await DB uh DB dot query dot U we want to query the workspaces and we want to find first like this where which will take a callback function like this and in here we get access to the workspace itself and um this will return equal right here okay so this has to return a Boolean basically so we're going to say equal workspace do um ID is equal to the user. ID okay workspace do owner ID so this is workspaceworkspace owner is equal to uh user. ID okay awesome and now we're going to check here if there is no workspace then we're going to return the following okay and we'll get to this in a second for now I'm just going to put uh return here just like this and if none of these cases are satisfied then we're just going to redirect which comes from next navigation to slash dashboard slash this is going to be a string literal so let's change this right here and when we say dollar sign brackets like this and say workspace do ID so what we're doing here is we're redirecting to the user to a new page uh with the current workspace that they have if they already have built one if not we're going to send them to create this workspace setup okay so what we're going to say here is we're going to return a div for now just like this and U inside this div we're basically going to put the following so let's give it a class name of BG dbgr class name of BG Das background like this height of screen width of screen Flex justify center items Center and inside this div we're going to create a new component in here we haven't created this so we'll just get to it in a second but it's basically um dashboard setup just like this okay and let's go ahead and build this component so you want to go in here into your components right in here create a folder here cuz we're going to have multiple things in here we can just call this something like dashboard Das setup like this and inside that we can oh sorry guys I put this in the lib folder so this should be inside the components folder like this awesome and in here we want to create a dashboard do um Dash setup TSX like this okay awesome and then we're just going to say ra fce and let's change all of this to dashboard setup just like this okay okay now let's go in here and let's import import this dashboard setup let's refresh everything awesome everything looks absolutely amazing okay now the next thing we want to do is we want to go back into our dashboard setup so let's go in here and we're going to do the following stuff okay so first let's create an interface like this dashboard setup props and in here we're going to say user is going to be of type O user like this we're going to say subscription is basically of a type okay and for now we're just going to create an object um and say or null we'll get to this in just a second guys all right let's first build this component out and then we'll set up the subscriptions uh right here okay and in here what we're going to say is react. functional component dashboard setup props and let's go ahead and get these from here which is the subscription and the user just like this awesome guys U we're going to create a card so we're going to show some sort of a card on the display screen so that um the user can create this workspace okay so let's go ahead and do that so first thing we need is the card component from shat and UI so let's scroll to where we find the card which should be this one and let's copy this npm and let's quit this and let's run um this Command right in here so since we already have the Shad CN UI card component let's let's go ahead and build that card component so we're going to say card which comes from UI card like this give it the following class names of width is going to be 800 pixels just like this the height is going to be screen SM is going to be h- Auto like this and inside this card we're going to create the card header like this and we're going to say card title inside this and in after this card title we're going to say card description like this and for this title we're we're just going to say create a workspace just like this and inside the description I'm just going to copy something in here and paste it and you can copy that from the GitHub or you can just type whatever you want okay and after the header guys we're going to have the card content just like this and this is going to have a form in here okay and this is going to be a different type of form because we're going to be using superbase storage so we're not using the chatsi and UI forms okay on submit um on submit like this is going to be equal to we'll just provide a function for now but we're going to get that from use form in a second okay and um after that in here we're going to create a div like this and this div is basically going to say um the following so it's going to have a class name of flex flex-all and GAP D4 okay awesome so first thing is I want to sort sort of render this component out so I'm going to go back to our dashboard and um let's pass in some of the information so it needs subscription and it needs that user so because I want to see what's happening here right so let's go to our um super base I'm going to show you guys something right here what you want to do is you want to click on the on any table you want to click on API and scroll to the bottom and you're going to see this generate and download types okay you can also do this through the through the CLI I also have a command um inside the script which you can run in package.json but I'm just going to go ahead and generate and download this these types right here and now I can shrink this and I can open this file superbase file but I'm going to show you what to do with it and we're going to copy this guys and we're going to go into superbase and we're going to create super base. types. typescript and we're just simply going to paste it in here okay and we're going to set up some types for this to basically get the infer for a select for example okay so this is what you got to do guys scroll to the bottom all the way to the bottom right here so first thing we're going to do is we're going to export um export a type called workspace equal to infer select model and we're going to pass in type of workspaces okay so this workspaces is nowhere to be found of course but um this workspace has to be imported from our schema file so so make sure you import the one from migration schema not your local schema okay import this just like this and now you'll see this is going to be of this type awesome right after this we're going to create uh another one for the profile okay which is user uh we'll just say user is equal to infer select model like this type of and this is going to be users like this okay which is coming from the migration schema again and then we're going to do export type folder equal to infer select model do type of and you want to do folders just like this so go ahead and take this up as a challenge and build out for files and for uh products and customers and subscriptions okay um there might be a slight change for the subscription and I'll show you how to do that in a second but go ahead and take it up as a challenge and build a types for that as well all right guys awesome hopefully you got it right if not this is exactly what you need to do so we're going to create an export type file and say a type of files and same for products type of products but for the price we have to do something a little different okay if you got this wrong it's okay it's fine uh but basically we're going to extend this infer uh select from here and we're going to say and products and we're going to put a product in here okay so if you see here it has something in here and then the customer is going to be type of customer uh type of customers and then the subscription is going to be subscriptions but we want to extend it with the prices in it okay we're also going to create an extra uh special type in here which is going to be called Product with price equal to product and prices like this and this is optional which is going to be price all right awesome guys and that's all we need now we have uh some of the types already set up so let's go ahead and start using them these so let's go back to our page. TSX under the dashboard and we're going to pass in these props right here so the first thing is the user so we're going to say user equal to user just like this but then we also need the subscription and the subscription is going to come from a different call so let's go up here and we're going to create this in in in our queries so let's say const like this data subscription then we're going to say error we'll just say sub subscription error like this is equal to await and we're going to put a call in here which is called get user subscription status like this we're going to create this query in just a second and in here we have to also pass in the user. ID because that's how we can get the subscription for that user okay awesome so what you want to do now is shrink your folders um because we're going to create this right here and head over to your lib folder and under your superbase create another file here called queries. typescript okay and inside your queries. typescript we're going to write the following so you want to say export const and paste that um oh I didn't copy it all right uh and say get user subscription status like this equal to an async function so we're going to name this as async and let me shrink this so you guys can see clear and in here we're going to say user ID is going to be a string and in here we're going to try bu and catch this right here so we're going to catch an error if any error exists and we're going to say const data equal to await DB so first let's import this DB and we're going to say query do subscriptions do subscriptions. find First and in here we're going to say where it takes a function in here and this function is basically going to give us s this is a subscription itself and um equal to equal to s. user ID equal user ID like this okay and guys for this to work you have to say use server up top just like our other server actions but these are queries so that's why we're putting in a different file okay and after this you want to check if data exists so if data exists you want to return a data with the data but as subscription like this which is under our superbase types so I'm just going to use this one also we want to return error like this with null okay all right so the error we were seeing here is basically we imported subscription from the wrong place so let's go ahead and do that one more time so it comes from superbase types not from the superbase um Library if the data does not exist then we're just going to return um an empty object like this with null in here and the error is also going to be null and we're going to copy this paste it in this error here and say error and also put our error right in here and we can also console.log the error so that we can actually see this now let's go back and let's import this from our actions so if you hover over this um you'll see subscription or null right after this subscription we're going to check if there is a subscription error then we want to return as well okay but if not then we're going to go down here and pass in our subscription and we see this error because our component is actually a server component in here so this of course needs to be turned into a client component just like this and if you refresh this everything looks absolutely amazing so as you can see here guys when we shrink this it's the full screen height and now it's just in the center this is exactly what we want so let's go down now right here to our card component you want to create another div like this and give it the following class names and we're going to say class name Flex item Center we're going to say Gap -4 and then inside this div we're going to create another div in here and say class name text- 5xl just like this and inside this one we're going to use an emoji picker which we're going to uh Import in just a second this Emoji picker is going to allow our user to select the emoji for their workspace so go ahead and open your terminal quit this right here just just refresh that and say npmi Emoji picker react just like this and hit enter and what we're going to do is we're going to go into our components and this is going to be a global component so we're going to create a new folder called Global and we're going to move this loader also in here and we're going to update all the paths everywhere in our file and in here we're going to say Emoji DP picker. TSX and in here we're going to basically say RFC and we're going to call this Emoji picker just like this and we're going to also create some props for all this stuff let's go up here and say interface Emoji picker props children is going to be react dot react node and then we also want to have a get value function which is optional so if we want to get the Emoji that was picked U from here so we're going to return void not coid it's void right here and in here we're going to say Emoji is going to be a string say react. functional component like this Emoji picker props and let's extract the children from here and the get value from here and inside here we're going to say route equal use router right here and again this is going to be a client component because we're using on clicks so use client right here and we're going to say const picker equal to Dynamic import so we have to dynamically import this guys so we're going to say damic like this from next Dynamic invoke this and this takes in a callback function um and this H this needs import and we're going to say Emoji picker react just like this and after this we're going to say const on click to basically handle the click when we change this Emoji we're going to say selected Emoji like this is going to be let's just say any because I don't know what it is right now and we're going to say if get value exist we're going to say get value invoke it and pass in the selected Emoji do Emoji just like this so what we're going to do here is we're going to say class name Flex items D Center and in here we're going to use a popover now the popover comes from shaty and UI so let's go ahead and just build it out for now and then we'll import it in a second okay so pop over and then we want to say pop over trigger after this we're going to say pop over content go to shaty Nui go to popover so let's search for popover and you want to click on this copy this and you want to paste it in your terminal and that will install your popover component for you and we're also going to go ahead and copy this import statement right here let's shrink this and let's import this right here and let's pass in the children and things like that so inside the trigger we're going to say children like this and after um and we're also going to give this some styling so we're going to say class name so let's say cursor pointer like this and for the content we're going to say class name p- Z border Das none and inside this component the popover content we're going to say picker and this picker is um the one we imported right here okay dynamically imported and this picker is going to actually we just use it as a closing tag and we're going to say on emoji click is equal to on click that we just created up here so now let's go ahead and render out this uh Emoji clicker component dashboard page. TSX and inside this dashboard setup okay right in here we're going to have the Emoji picker right in here so first let's import our Emoji picker and in here we're going to basically say get value is going to be let's just set a function for now and we'll come to this in a second and then um right after this we want to say selected Emoji which we're going to create in just a second so this is going to be a state here that's going to hold the selected Emoji so let's go up here and we're going to say const selected Emoji set selected Emoji just like this and this is going to say use state so we'll just set it to empty for now and in this Emoji picker we're going to pass this selected stuff once we get the value so what we're going to do in here now at the bottom in your emoji picker get value we're going to set the state to set selected Emoji to the Emoji that comes from right here so after this part right here guys what we're going to do is we're going to create another div and we're going to give it a class name width to full and in here let's create a label that comes from UI label and inside this we're going to say HTML 4 and we're going to say workspace name and inside uh and also give this some class name of text DSM text- muted D foreground and in here we're going to say name so these are basically the forms that we're going to create right now that's why we built this form up here so let's go to this part right here and what we want to do is we want to create an input and what we want to do is we want to create an input right here so we're going to say input that comes from UI input and this input is going to have an ID set to workspace name the type set to um text not string um and then we want to have placeholder set to workspace name the disabled we're going to come to in just a second so uh let's actually create our use form hook so that we can get access to all these variables all right so let's go up here up top and say const use form that comes from react hook forms here we're going to pass in an object that has mode set to onchange default values set to an object and this object has to have logo which is going to be a string which we're going to do right now um but we also want to have workpace name right here set to an empty string too and this logo is actually only for pro members so we're going to have that restriction where only Pro members can um upload a custom logo for the workspace all right guys so I made a small error here this is actually spelled as Flex column so that should all right that should fix that awesome cool and in this input field we're basically going to set in another class name called BG transparent okay I would actually want to take this and I would want to probably go into the component itself and change that let me see if I can do that so right here we're saying the following so BG back ground right here let's remove this and set it to okay transparent just like that and let's make sure that is applied successfully and we need the is loading guys so we're going to get register we're going to get handle submit and reset and also let's get the form yeah let's get the form State and this will give us is submitting but we're going to set that to is loading and then we want errors also for this input field we're going to set the disabled to is loading just like this next you also want to use the spread operator here for register and you want to invoke it and you want to pass in the name for this which is workspace name just like this so basically this ID guys copy this paste it in here after this pass it an object and say required is set to workspace name is required below this input you want to say small and say class last name text- r- 600 and for this one we're going to say errors. workpace name. message and a two string so this is going to basically render out our um our error message okay so we see something here remaining connection slots are reserved for non-replication super user connection so what is this so let's just go ahead and refresh it and see if that fixed our problem I refreshed all right awesome so uh if you see that guys just refresh and you should be good to go come down after this small right here this div this div and right after this one you want to create another div okay and in here guys we're just going to copy this entire thing so copy this all the way to the small right just like this and inside this div just go ahead and paste that and you should see that right here okay so this issue right here is because we don't have an emoji so let's just put um like a workspace Emoji like a briefcase case um just like this in here and that should render all right awesome that's what we wanted so now when you click on this guys you see this it basically shows um you know this stuff okay so that's it and what we want to do now is we want to scroll down here and right after this where where we created this logo we're going to change this one to workspace logo just like this and you want to you can also have the same thing here this is fine want to change this to workspace logo like this and this disabled is actually going to be is loading or subscription dot um subscription like this do status is not equal to active Okay so right here we have it set as an empty object so now we can say subscription right here and this should not throw an error anymore and what we're going to do here is we're going to change this one to workspace load logo like this so copy paste that this is going to be called a file and we're going to say accept equal to image/ Star and um now we need to change this right here so this will be workspace logo um actually it's going to be called logo so what we can do is let's change this ID to this and this to logo to and register logo just like this awesome guys all right guys so I just took a look look at this and I found out some of the places where we made an error so the first thing is the way we're using field values here is incorrect this is not the type we need to use we actually have to create a form type and um that is the first problem here the second thing is that title was actually undefined because value dot this spelling error does not exist okay we're going to scroll up top right up here and we're going to just create a type okay so if you remember we had a type file right in here under types so we're going to say export const create workspace form schema equal to Z doob we're going to invoke it like this and inside here workspace name which is going to be z. string like this describe this is going to be the workspace name like this dot minimum so we have to have minimum of one and we're going to say workspace name must be minimum of one character okay just like this and then right after that we're just going to set a file which is going to be equal to z. NE so z.n just like this and you can hover over this and you can see this stuff okay um the reason why we're setting this to any guys is because if you use this on the server side file is going to cause some issues so now let's go back to our types and let's import this type right here so instead of field values we need to use our schema and let me just import the schema all right so let's go up top and let's import the create workspace form schema which comes from lib types and then we want to go in here and we want to say z. infer like this and we want to say type of like this and we want to say the new schema which is create workspace form schema just like this and this logo is showing an error because in our type we actually have it named as file so we're going to turn this into logo and let's go back into our file and see what happens here awesome and now we're going to copy this right here and we're going to paste it even for our submit Handler and now we're going to see some errors here and this is what we had wrong which is workspace name so let's go back to our application let's just refresh and we're going to um just type in some stuff here so we're just going to say fake test and we're just going to test out out this file for now I'm just going to upload something here we're just going to say create workspace awesome it did that and it successfully sent us to the page that we need to land on but of course the page does not exist so we're seeing this error but let's first make sure our file was uploaded successfully there we go right here we have the new entry being made and if we go into our storage and let's look at the workspace logos all right there was a quick error guys all right guys so I just looked at this error and it turns out uh we did a couple things here too so apart from these errors we basically needed to set up some sort of policies to accept in here so what I did was um go ahead and just click on new policy and hit full for and hit for full customization and you want to scroll here to the bottom and just click on select insert update and delete so select all of of them and I'm just going to unselect these cuz I already did it and then you want to just give this a name so you can say allow all access just for now guys we'll change all this stuff later it's not very important okay so go ahead and do that and then just hit review and it's going to take you to um this so I'm just going to select all this for now so I can show you guys what to do I'm going to also select the authenticated roll and just hit review and it's going to give you this just go ahead and hit save policy all right guys cool so I'm just going to cancel this get out of this and then you will see these policies right here okay and if you don't know how to access this you want to go into your storage and then click on policies right here and then you can see all your policies for your buckets okay so that was the problem that we were facing and um I'm going to go ahead and show you guys that it actually works so let's go ahead and delete this file from here and you can see the logo workspace logo and it says dot there and now if you go into the database right here under files under workspaces you'll also see everything in here including the workspace logo and the item itself so let's go ahead and delete this row so I can show you that it actually works and let's go to the browser let's go one page behind let's just click on submit right now we're going to create a workspace name so we're just going to say test workspace and then we're going to change this just upload a file so scroll to the bottom click on this file just hit open and then we're going to create the workspace it's going to upload it and send us to another page which we're just going to set up of course the page does not exist right now um but if you go to our database and you click on workspace logos now you will see our workspace logo has been uploaded here successfully before we move forward I just want to show you something so you need to add this images inside your next config.js go to your next config.js and you want to add images here and the domains is basically basically going to be equal to the following so you see you have this right here right you want to select this part and super base. Co and just paste it inside an array um just like this right here okay an array of strings just paste that in there that's the only way you're going to be able to uh access these domains to get the images okay don't forget to do this or else your images are not going to show up there we go it also has the dot here so you can split by the dot and you can take this element and you can do whatever you want to do um with it okay and if you also go into the database entry um the workspace table entry you will also see the data in here awesome guys let's move on now so I'm just going to go ahead and delete this too so open your folders I'm just going to shrink this and you want to go into your app directory right in here and you want to open your main folder and here you have your workspace folder right so this um uses a d Dynamic param you're going going to use this ID to capture what the user is trying to access okay so inside this go ahead and create a page. TSX just like this and inside this we also want to create a layout. TSX so say layout. TSX just like this and you can just copy this from here if you'd like go to layout paste it and in here just remove this stuff we don't need this anymore and we're going to put some stuff in here okay so just just replace this to a div for now all right awesome so layout props children and pams and we're going to get to this in just a second and in your in your page you want to return rafc and let's just return the workspace page just like this and you're going to see the workspace page here because now we have that page rendering okay awesome so in this page guys we're going to basically render out a quill editor and so in this page guys we're going to to render out our editor but um let's first work on the layout page because we're going to work on the sidebar first okay so in the layout page what you want to do in here is you want to basically edit this stuff so let's change this back to a main actually and in here you want to First say Flex overflow hidden height is screen width is screen width is screen just like this and inside this we're going to create a component so the first component we're going to create is called um the sidebar okay so we're going to say sidebar don't import this by mistake okay just type in sidebar component and this sidebar component is going to take in some params and the params are basically this ID that comes in guys the dynamic ID that comes in there okay so params equal to and we're just going to say params like this awesome and for this children we're actually going to render it slightly different so here first we will eventually have the mobile sidebar right here so we're just going to skip this here and we're going to return a div with a class name to dark border neutrals -12 sl70 border-left D1 pixel like this and then we want to have width Das full relative overflow scroll and um that's about it okay and what we're going to do here is inside this we're going to render our children okay and these children components here are basically the editor itself so it's going to be wrapped with the sidebar component so let's go ahead and create this sidebar component so you want to go ahead and open your components and create a folder here called sidebar just like this because you're going to have a bunch of stuff for the sidebar okay and inside this you want to create a sidebar. TSX file file and um let's also say rafc and say sidebar just like this okay and let's also create our interface right up here interface sidebar props is going to be params which is going to have workspace ID which is set to a string like this and um we also want to have the class name set to a string so this can be dynamic okay because we might want to pass in some uh styling for this sidebar and in here we're basically going to say react. functional component and we're going to do this and say sidebar props sorry and let's pull the pams from here and the class name from here awesome and what we're going to do in here is we're going to say const super base equal to create server component client like this and we need to pass in the cookies so we're going to get the cookies from up here so so import cookies from next slhe headers next slhe headers just like this and pass in the cookies right in here so this is going to create our um our instance and first thing we want to do is we want to check if there's a user after that we want to check their subscription status okay subscription status and then we also want to check um the um folders We want to get access to the folders because if the user Direct ly accesses this page we want to generate the folders for the sidebar and then we're going to check if there's any error and if there's an error we're going to redirect them back to the dashboard page okay and uh finally we're also going to get all the uh different workspaces which is the private the collaborating and the shared workspaces and then we're going to go ahead and render this out okay so let's go back to our layout. TSX and let's import this site sidebar so it needs the params right here okay let's just refresh this it accidentally imported sidebar from a different component so we're going to do components sidebar just like this and there you go now you can see we have something on the left side okay and it says sidebar right in there awesome now let's go back into our sidebar component and let's build out our Logic for the sidebar so first let's get our user so we're going to say const data like this and this is going to return user like this and this is equal to await superbase do.get user and this needs to be an async function right up right up top and um what we're going to do here is we're going to say if no user we're going to return okay then we're going to say const data is workspace folders so we're going to basically get the folders here let's first get the subscription status yeah so const data and error equal to await get user subscription status just like this and this needs access to the user. ID like this awesome and um right after this we want to also get the folder so now we need to create a query for that so first let's write this here so we're going to say const data and error is equal to await get folders and this will take in the ID for the workspace right so we can just say params workspace ID like this and right here this error is going to collide with this so we're going to call this subscription error like this subscription error and this one is going to be folders error okay like this and this data is going to be called subscription and this one is going to be called the workspace folder the workspace folder data just like this okay so subscription data let's give this a better name awesome and now what we're going to do here is we're going to check for the error so if error um exists then we're going to redirect from next navigation okay and say dashboard so we want to send the user back to the dashboard and this error right here is going to be um subscription error so we're going to say subscription error or the folders error just like this so here now we need to create this get folder action so let's go ahead and do that in our queries file so open up your folders go into superbase and then go into queries and right here we're going to basically get our folders so we're going to say export const get folders equal to async function like this and this is going to get the workspace ID which is going to be a string and in here we're going to say is valid okay is valid and equal to validate which comes from uu ID and we're going to pass in the workspace ID just like this and we want to make sure that this is actually a valid uyu ID right so if it's not valid then we want to return the following which is a data with null and error set to an error like this and if this is true uh I mean if this is okay then we're just going to do a catch right here and we're going to get the error here and we're going to say const results equal await DB do. select invoke it. from like this and in from you want to pass in the folders which comes from migration schema and you want to say umt order by folders do folders. created at like this and then after this you want to say where now we're going to say where equal like this and you can import equal from drizzle orm like this and this needs to be folders. workspace ID is equal to the workspace ID that we passed in okay we're going to say folder or empty array just like just like this and let's import that from superbase types so now you can see the return data type okay awesome and after this we're going to basically say return data is going to be results and error is going to be null like this copy this and here we're going to say error is error like a string right here and here is going data data is going to be null awesome guys so now let's go ahead and see um if if we can import this so to get folders right here and let's refresh the page and also we need to refresh this real quick so let's just do this here and refresh this so our Navar is basically going to have the workspaces on top it's sort of like a drop down where the user can click on the workspace and select the workspace they want to go to right so before that we will need to fetch these workspaces from here so that we can pass it down into those components so let's go ahead and do that too so we're going to say const private workspace actually let's first create the um um the queries okay so let's go into our queries file which is inside superbase right in here scroll to the bottom and we're going to say get private workspaces so const is uh get private workspaces is equal to this we're going to set this to this and also export this function here and now we want to basically get the user ID here so user ID is going to be a string just like this so we're going to say if there is no user ID just return from here and we want to return data uh actually we'll just return an um an array here so the return type is going to be slightly different and here we're going to say const private workspaces is equal to await db. select invoke this and you want to pass in this object cuz we um want the following which is these okay which is workspace ID so ID is workspaces doid created at is workspaces created at workspace owner is the workspace owner title title icon ID icon ID data for data and in TR is going to be this and the logo is going to be the logo right here okay and after this right here you want to do Dot from just like this and and you want to say workspaces like this where and not exists db. select like this do from collaborators which we haven't created yet so let's go ahead and build that collaborators right here so what this collaborators table is it's a table that has information about collaborating users along with their workspaces that way we can tell when a user is a collaborator of another workspace so let's go up here and let's go into our schemas and let's go ahead and create that collaborators table right here all right so let's go up here and say export const so so make sure you're inside your schema file under superbase and you want to say export const collaborators equal to PG table set this to collaborators like this and this is going to be an object like this and inside this object we're going to have the column fields which is workspace ID which is going to be a uu ID like this and we're going to set this to workspace ID and this is going to be not null like this and this is going to reference something else guys so what it's going to reference is basically it's going to reference the workspaces doid just like this and we also want to provide the on delete Cascade so on delete Cascade for this just like this awesome and after workspace ID we want to say created at is going to be a timestamp copy this from uh maybe the files table scroll down here and just say created at like this create at with time zone and mode set to string and the next one we want to have right after this is default now invoke it and you want to also pass in not null like this okay and then after this we want to say user ID is going to be uuid which is user uncore ID just like this and here we need to sayot null do references users migration schemas dot doid like this and we also want to set the on delete to cast skade just like this awesome guys so don't forget we need to also Commit This so I'm just going to um refresh everything quit the server as well so I went ahead and closed the server and um I opened my terminal and we're going to say npm run generate just like this and that's going to generate our SQL file for us with the three columns that we just wanted right in here and now we can do npm runev and refresh our browser and if everything worked well well we should see no issues in here but I do see some problems in here it's saying um duplicate key violates unique con constraint okay I'm not sure what happened here guys but I saw the error and I also saw migrating clients and successfully migrated and it also pushed the migration so let's go ahead and see if that actually okay so it looked like it worked I'm not sure what happened there guys but that might just be some sort of a hiccup that's fine let's just go ahead and Shrink this and let's go back and start working on our code so let's go back to our queries and now we can bring in the collaborators that we we that we wanted initially um right in here okay and what we're going to say here is we're basically guys we're trying to see if there is a collaborator okay but you don't want it because private workspaces cannot have a collaborator okay so we're going to say from collaborators do where like this invoke this and pass pass an equal to like this and say collaborators do workspace id workpace id we had this one which is not exist and then we want to have the equal right here where workspaces do workspace owner is um equal to the user ID right in here so we only want the workspaces that are for this specific workspace um owner right and we can just do something like this we can just say workspace um let's just say workspace like this so this will have some data type right in here it's just going to be an array of that one okay array of uh workspaces or we can just say yep just like this awesome so private workspace is just going to be an array of these objects right here okay right after this make sure to return the private workspaces like this okay and uh now let's also go ahead and do the same for the collab collaborating workspaces so we're going to say export const get collaborating workspaces right up here this is equal to a function and this is going to be async right here and this is going to take in the user ID which is a string so user ID like this which is a string and in here we're going to check if there is no user ID and if so we're just going to return an empty array okay and then we need to say collaborated workspaces like this is equal to await DB do select and we want to put in the following it's basically the same thing as we had up here guys okay so we're going to put these in here and then we're going to say dot from like this and we want to say users and then we're going to do an inner join um let's import this inner join right here and this needs collaborators and then the equal to so on what which is users. ID and that should be equal to the collaborators uh do user ID like this and after this we want to say dot another inner join like this um with the workspaces on basically collaborators do workspace ID is equal to the workspaces doid like this okay and then after this we want to also give a wear condition right here so we're going to say where invoke this and inside this we're going to say equal users. ID equal to um like this in here users ID is equal to user ID just like this okay so for the only for the same user and again we can just return this as um workspace so an array of all the workspaces awesome there we go and let's go ahead and also return the collaborated workspaces just like this and let's do the same thing for shared workspaces too so export const get shared workspaces equal to this is going to be a function here too and let's set this to async and we need the user ID in here which is going to be a string and we're going to check if there is no user ID if there is not we're going to return and basically we're doing the same things guys just a slight bit different and I'll show you what you what needs to be uh done differently okay copy this and paste it so we can save some time right here we're going to get the shared workspaces we're going to select distinct okay select distinct so we want to do we want to get these things right here from the workspaces order by workspaces doc created injoin collaborators where the on the workspaces ID and the collaborators workspace ID okay and then we want to check where the workspaces um the owner is the same and we're just going to return that so we're going to return this as workspace just like this okay now let's go back to our sidebar component and after after this guys we're just going to say const um like this private workspaces and then collaborating workspaces right in here and then finally shared workspaces like this is going to be equal to um we're going to do await promise.all um like this promise.all and we need to invoke it and we need to pass in all the promises and what we're going to pass in first is get private workspaces invoke that and pass the user. um user. ID like this and then we also need to get the others so we're going to say get collaborating workspaces and pass in the user. ID like this and after this we need the get shared workspaces and pass in the user ID in here too just like this awesome so let's look at this Okay cool so now we have access to all these workspaces okay we don't have any errors there looks good and what we're going to do here is we're going to return a sidebar okay so this sidebar is basically going to have a side like this aide and it's going to have a class name of hidden SM set to flex like this and then we want to say from small from SM devices Flex call then we want to have width set to 280 pixels and then we want to do shrink and then we want to do shrink d0 padding -4 md- Gap is going to be four then we're going to say um exclamation justify between so we want this to always be important and now since we're using class names we uh from the props we want to copy this and we want to pass this into Tailwind merge uh right here guys so say tww merge like this and pass this string in here and after this um string here we're going to also pass in our class name from the props okay and inside this aside we're going to create a div in here and uh we're going to pass in some information in here okay so the first thing we're going to have is the workspace dropdown guys it's sort of like a component up here so so let's go ahead and build that component out all right guys so go ahead and expand the sidebar and now you can see it right here the component we're going to have is workpace drop down just like this let's go ahead and create this component right in here go into your components folder open your sidebar and in here you want to create workpace drop down. TSX and you can do rafc and change this to work space drop down what this component is going to do is basically it's going to allow the user to select between the different available workspaces so let's first go ahead and create the interface workspace drop down props it's going to take in the private workspaces workspace but an array of these workspaces or it's just going to be empty like this and then here we're going to say shared workspaces is going to be of workspace type array like this and also empty like this collaborated workspaces is also going to be the same thing guys just like this and then the default value is going to be workspace or undefined go ahead and say react. FC and say workspace dropdown props and now we can extract those from here so we're going to say private workspaces collaborating workspaces and shared workspaces we see a an issue here and I think there's just a spelling error okay cool we're going going to create some states here so we're going to say const selected option and set selected option use state so again if we're using use state in here we need to go ahead and set this as use client so use client up top and this is going to have the default value guys so the default value comes in from here which we need to extract and we're going to Simply put that right in here and right after this create const is open is going to be and also set is open just like this is going to be equal to UST state which is going to be false by default okay we also want um the dispatch from here because we're going to set all the workspaces once this component is invoked okay so um that's why we need this so we're going to say dispatch and state is equal to use App State invoke that and now we have access to that okay so first let's create a use effect and what this use effect is going to do is it's basically going to check if our state has any workspaces okay if it doesn't have any workspaces then it's going to go ahead and set it to um whatever we get from the these props right here let's copy these and pass these as dependencies so collaborating workspaces and shared workspaces just like this and in here here we're going to say if state. workspaces length like this so if there's nothing in here guys then we just want to call dispatch we want to send the type set to set workspaces which we'll create in just a second set workspaces this is also going to have a payload so go ahead and create this type go into your uh file which uh your Libs file go into providers State provider and let's scroll all the way above and let's create a set workspaces type right here create an object and save that and let's go ahead and just actually uh just copy this right here so that's going to be easier and we're going to say set workspaces is going to have a payload and this payload right here is going to basically be an object with the workspaces set to an array of app so app workspace type like this or this can also be an empty array and here we're going to create the reducer for it case where we have set workspaces we're going to return an object with everything in state and the workspaces action. payload do workspaces and here we did a small problem so let's just go ahead and fix that so instead of workspace it's going to be called workspaces so now let's come back here and pass in the payload and this payload is basically going to be an array like this and this array is going to have everything in private workspaces everything in shared workspaces and everything in collaborating workspaces but the issue here is we don't have the folders for it and each folder also has to have a file right so we have to provide these um options right here after this where we have this array we're going to say map and this gives us access to the workspace itself and we're going to uh we're going to basically return a new object with with everything in workspace but we're going to set folders to be an empty array okay so it seems like there is some sort of a type error so I'm going to go ahead and look at what's causing this all right so the problem here is we need to say workspaces and then we have to provide that value go ahead and just remove that and this has to have workspaces like this and then we can provide this and this should be perfectly okay and now let's go back into our sidebar component and let's go ahead and import this right here so there's another error there so I'm just going to go in here and workspace drop down this has got a change so um what we're going to say here is drop down like this and drop down like this right here and this needs the private workspaces which is going to be equal to private workspaces shared workspaces finally collaborating workspaces so the issue here is our action our server action for the get shared workspaces is not returning anything here by default default so we want to put an Mt array just like how we did for collaborating workspaces okay and that should actually solve that problem and the default value here is going to be slightly different so let's go and say default value is equal to and what we're going to do guys is we're going to create an array and we're going to just use the spread operator for all for all of these private collaborating and shared workspaces and then we're going to find one of them where the workpace is of workspace doid is equal to params do uh. workspace ID just like this okay so this way we don't have to make an unnecessary API call just like that cool awesome guys now back inside our workspace dropdown right after our use effect hook right here we want to go ahead and create a handle select okay and this handle select is basically when we select that component uh right when we're changing our selection option we're just going to use this so we're going to say handle select equal to a function like this and we're going to say option which is going to be of type workspace and here we're going to set selected option to be the option in here and set is open to be false okay so if this doesn't make any sense don't worry about it I'm going to uh get to that in just a second so let's go ahead and remove whatever is being returned here and let's return a new and we want to give it the following Styles relative inline block text- left and inside this we want to create another div and in this we want to say span on click and this is going to be a function that is just going to set is open to the opposite of is open so we don't even need this so we can shrink this one more line here okay and inside this span we're going to say selected option if something exists here we're going to do something here if not we're going to going to do something here so if this is true what we're going to return is selected workspace and this is another component that we're going to go ahead and create so let's go into our files back into our sidebar and let's create selected workspace TSX like this and say ra fce and change this to selected workspace um just like this create the interface selected workspace props a work space which is going to be of type workspace onclick and this is going to be a function that returns void we're going to first say con superbase equal to create client component client and we're going to just invoke that like that and after this we want to say const workspace logo and set workspace logo equal to use State like this and in here we're going to just have um slash Cypress logo.svg this needs to be a client component so let's go up here and say use clients like this let's also refresh this we're having this error again here npm run Dev and let's uh reboot that one more time okay and yeah we're going to get the selected workspace is not defined so let's quickly finish this so we want to say use effect pass in the workspace right here so we need to use this interface so let's say react. functional component pass the selected workspace in here and you want to extract the workspace from here and also we have an onclick and in here we basically want to see uh we want to say if workspace do logo if this exists const path equal to superbase do storage superbase like this we want to say superbase storage. from we're going to do this real quick and we're going to say workspace D logos like this and then we're going to say get public URL and um we're going to pass in the workspace do logo like this in here okay this is the way to get a public URL for the workspace and then we're going to say data dopu URL just like this have to say set workspace logo to path now let's go in here and let's make some quick changes right in here to return our component basically okay it's a really small component nothing crazy in here so we're just going to have a link component like this which comes from next link href set to dashboard slash and this is going to be a string literal right here and we want to say dollar sign workspace ID so this is workspace doid like this so when we click on this link guys it's going to take us to that specific workspace okay and um the other thing is onclick not on onclick like this and that's going to be an aror function like this and that's going to basically check if the onclick exists um right here so if onclick exists then right after this we're just going to say on click and we're just going to fire this um right here then we're going to have a class name here and first we're going to say Flex rounded MD uh hover uh background- muted transition all Flex row P2 Gap 4 justify Center the cursor pointer items Center and the margin y of two inside this we're going to have an image tag and the SRC is going to be set to workspace logo alt tag going to be the workspace logo just like this width is going to be 26 and the height is height is going to be 26 as well and finally we want to say object fit just like this okay and of course we have to send set this to cover right here so let's create a div here and say class name is equal to flex and flex D column and in here we want to have a paragraph with a class name set to text LG with 170 pixels overflow hidden overflow ellipses and widespace no wrap okay and inside that we're just going to render out the workspace do tile let's close this quickly and let's go ahead and import this component right here right now we need to also pass in those new values that we just uh those the props for it right so the works the selected workspace is going to have the workspace and that's going to be the selected option so whichever one we selected so the onclick has to be actually optional because yeah so let's go up here and just say optional like this and that should actually fix our problem yep okay let's come back here after this we're going to render this but if this does not um exist we're going to say select a workspace like this so right after this one say is open so if it is open we have opened the div then we're going to render out the following a div again and let's give it the following class name origin top right absolute w- full so with full rounded MD Shadow Das MD Z50 height is going to be 190 pixels BG is going to be black uh but only 10 back drop Das blur and this blur is going to be LG we're going to say group we're going to say overflow Das scroll border D1 pixels border Das muted just like this okay and um as you can see we already have the workspace logo because this logo was actually uploaded to superbase storage right but of course for everyone else uh for uh for you know the um the regular users they're not going to have a custom logo if they don't have the plan so let's go go ahead and create another div in here and we're going to give this a class name of rounded DMD flex flex-all and then we want to create another div and this one is actually going to have um just one styling it's an important one right here so that this one shows so it's just exclamation padding to and inside this we're simply going to say private workspaces do length so we're going to convert it to a Boolean right there and we're going to return the react frag M like this and inside this react fragment we're going to have a paragraph tag and this paragraph tag is going to have text- muted D foreground just like this and inside here we're going to say private okay so it's going to be the titles for our workspaces we want to also just you know we can just render out a horizontal rule just like this and then we want to say private workspaces do uh map for each of these we're going to return something so we're going to get the this option here and then we're going to return a selected workspace again right here and this time actually let's just make this a closing tag so it looks better here and then we're going to say key equal to option. ID like this and then we want the workspace to be equal to the option itself finally we want the onclick Handler and this onclick Handler is going to be our handle select that we just created um um okay we also need to pass in this here so go back to your selected workspace component and in the onclick you want to just select option like this and it's just going to be a a string oh actually it's going to be a workspace so let's go in here and just say workspace like this and then let's go back to our drop down component and this should actually fix the problem the issue here is that this onclick is not getting access to this so we're we're going to select this and pass in our workspace right in here and then right after this now we're going to check uh the shared workspaces so go ahead and take this up as a challenge and build the same for your shared workspaces if you can't do it no problem come back to this video and I'm going to show you exactly how to do it all right hopefully you got this correct if not don't worry about it guys I'm going to show you what you need to do so it's literally the same thing you can you can literally copy this and paste it right below but you just have to change shared workspaces and then do length like this and change this one to shared and um everything else is going to be the same but make sure you're rendering out the shared workspaces and the same thing for the collaborating workspaces as well inside this one we're also going to have a create a workspace at the bottom so let's go ahead and build that after this div we're going to create a custom dialog uh trigger component which which we are yet to create go into your components so let's open this this here go to your to your Global folder and you want to create a custom- dialog. TSX like this and do rafc and say custom dialogue trigger component just like this this component is kind of like a wrapper guys so we're going to use chat CN ui's um uh dialogue components and we're going to sort of create our own custom dialogue trigger so that we can have different children instead of just you know writing in the whole component in one section go ahead and open up Shad CN UI and in here you want to look for the dialogue component okay not the alert dialogue go to dialogue right here copy this npm copy the npm and then hit enter and just paste it in here copy these right here and we're going to go to the top of the file and we're just going to paste it right here so this interface is going to be a little more so it's custom dialogue trigger props a header the content which is a react. react node the children react. react node description for this custom dialog trigger and the footer and the class names okay and these are optional too so make sure you have these question marks right here so go ahead and type this out if you need some time and then here we're just going to say react. functional component and we're going to pass in the custom dialogue Trier props and let's go ahead and extract all of these values from here and when you come to this return statement remove this div and return the dialogue like this okay and this dialogue again is coming from components UI dialogue and in here we're going to have the dialogue trigger right here like this and after this we're going to have the dialogue content like this and inside the content we're actually going to have a our dialog header and inside the header we're going to have dialog title after that dialogue description like this and now let's go ahead and fill these in so for this one we're going to say class name equal to clsx import that and invoke it and then you want to just pass in an empty string for now and you just want to say class name like this okay and inside the dialogue trigger we're going to pass the children guys right in here so what this is saying is basically we can wrap our children in that so when we click on that on the children itself the whole children element is going to be a trigger so it's going to bring up the dialogue on the screen so now let's go in here and say class name height screen block SM height Dash um Das 440 pixels overflow Das scroll with- full and we're going to pass in the header like this and our description is going to be description and the footer right here is actually going to be in uh sorry the content is going to be right in here okay the footer is actually optional so you can pass that if you want to uh but since we're not going to use it actually let's just go ahead and remove that for now and now let's go ahead and run npm run Dev if you haven't already and let's uh restart our server and let's import this custom dialogue trigger right here so you're going to say header equal to and the header is going to be create a workpace like this and then we're going to have content equal to the workspace Creator which we don't have right now so we're going to create that component as well and let's go ahead and first pass in the description so the description is just going to be a bunch of strings right so it's going to be workspaces give you the power to collaborate with others you can change your workspace privacy settings after creating the workspace too so so let's go ahead and build out this um workspace Creator component so before that guys I just want to prevent this error from happening right here maybe just create a react fragment go into our components which is uh um actually under the global components create a new file call it workspace dascreator you can say RA fce in here and let's change everything to workspace Creator just like this so what we're going to say here is const permission and set permission so what this permission is guys so let's change this to permissions and set permissions so what this permission is is that you can set the permission of a work space to be shared or it can be a private workspace okay so we're going to say use State and we're going to set the default value to private okay and then um since this is again using States here we want to make this use client right up top and then we say we want to say const title like this and set title right here equal to use State and this is going to be an empty string as well collaborators and set collaborators and this is going to be um users like a user like this from our superbase types okay so it's going to be an array of users for the collaborators const user set user like this equal to uh use State actually uh what I'm going to do guys is I might actually create a global um yeah let's go ahead and see if we can do that so yeah let's just go ahead and create another uh provider in here and we're going to call this superbase user provider okay. TSX set this to a use client component and then you want to uh create the context so this is going to be type supera base user context type is equal to uh we're going to have the user which is going to be of type O user like this from superbase or it's going to to be null and then we're also going to say subscription here because we can get some subscription data and we're going to use the uh subscription type that we created which is right here in superbase type so it's going to be subscription type or we're just going to say null and um this is where we're just basically going to get access to the user based of data and then let's go ahead and create the context so this is going to be super base user context is going to be equal to create context and and um inside this we're going to basically pass in the supera base user context type and in here we need to pass in an object and we're just going to say um uh what is that user is going to be null for now and the um subscription is going to be null again right like just like this okay and after this we're going to say export con use superbase user is equal to we'll just create create this right here and this is just going to Simply return us use context like this from react and it's going to return the superbase uh user context just like this so we're going to create the superbase user provider here um let's just create some interface here we're just going to say interface superbase user uh provider props is going to be um children children like this which is going to be react do react node and then we're just going to say react. functional component and we're going to say super user uh provider props and let's go ahead and extract children from here okay return like a fragment like this and that's going to solve that problem okay and what we're going to do in here first is we got to fetch the user details we also need to fetch the subscription details right so we can get to the subscription in a bit but um let's first B basically get to the user part so what we're going to do here is we're going to create a use effect and this use effect is going to have an error function um and a dependency array right here const super base is create client like this component client uh we're going to pass in superbase as a dependency in here const get user is equal to a function like this it's going to be async function and we're just going to invoke this get user right here and inside this we're going to say const data and this is going to return the user is equal to um await superbase do.get user like this let's go ahead and invoke that and in here guys we just want to check if user exist and if user exists we're just going to set the user which um we haven't created yet so let's just say const user and set user user equal to use State and this is going to be of type O user or null right so the default value is going to be null in here so we're going to set the user to the user right here and then we're going to say const data and error equal to await get uh user subscription status and um this is is going to need the user ID okay so let's just say user ID like this if the data exists set subscription uh which we also need to create up here so that's just going to be uh very s very similar to this it's just a state with subscription set subscription and that use state is going to be of type subscription or null okay so let's get that subscription from here so we're going to say set subscription like this and we're going to set data in here okay and if error ER so if error exists in here then we're going to return a toast toast from Shaden UI so let's use that okay so we're going to say toast equal use toast like this and in here we're basically just going to invoke toast and pass in the title we're going to pass this uh right here so we're going to invoke toast and we're going to say title unexpected error oops an unexpected error happens and whatever whatever they're already going to get rerouted so we don't have to start rerouting the user unnecessarily okay and we also might need this toast I'm not sure if it's needed but we're just going to pass it in here and here we're just going to return the uh superbase context. provider and in here we're going to pass in the children just like this and for this we need to pass in value and this value is going to be the user and subscription just like this awesome stuff guys so now this is going to be very helpful because we can get the user data data and the subscription data at any time in our application so go to your app directory go into layout. TSX and you want to wrap all of this U with the state uh provider inside so you want to say um superbase user provider like this and you want to just pass this in here just like this okay awesome so now let's just see if this is actually working so when we get the user we're just going to uh console log the user so we're just going to say console.log user in here let's open the terminal the console I mean and let's just um save this refresh this page and there you go you see the users information great stuff guys all right now we can reuse this within our components so let's go back to where we stopped so going back to our workspace Creator which is under a global components now we can use that information that we have so we're going to say con user and we're going to say subscri actually we don't need the subscriptions yet so we're going to say equal to use superbase user and invoke this just like this so another thing I do want to point out is this user is actually of type off user and the problem is it's not going to have the um the updated URL for the Avatar and all that kind of stuff okay but that's okay we can do that when we need to at that time for now let's just go ahead and um just create this component right here next you want to go right below this and say const router is equal to use router like this from next navigation and then we're going to create the following functions so const add collaborator like this is going to be an arrow function with the user set to user that comes from superbase types going to set the collaborators to be an array with everything inside collaborators but we're going to have the new user right in here and then const remove collaborator right here is basically going to be another function like this and this function is going to get access to the user as well and in here we're basically going to set the collaborators to be collaborators do filter cuz we're removing it right we just call it C and then we want to say c. ID is equ is not equal to um user. ID okay so we're just going to filter our current currently existing collaborators okay and right here you want to return a div and we're going to give it the following Styles so Flex Gap 4 flex-all just like this and inside this we're going to return another div and inside this we're going to return a label like this from UI label not radic UI and this is going to have HTML 4 set to name and in here we want to have the class CL name too for this so class name just like this and this one can be text- smm and we want to say text- muted D foreground and inside this one we're going to just say name like this so this is basically like a workspace Creator form guys it's kind of like a form that's going to allow you to create a new workspace okay so now let's go to our workspace dropdown and let's simply import this component so we can look at what we're doing right right here just like this let's go ahead and do this uh render out that stuff here so we're going to say class name and we're going to set it to flex we're going to say transition all we're going to say hover background muted justify center items Center Gap two padding to and the width full and inside this div we're going to create an article like this and this is going to have the following class names so we're going to set it to text slate 500 rounded full B BG slate 800 width four height four Flex item Center justify Center and inside this guys we're just going to return a plus icon just like a plus like this and after this we're going to say create workpace okay so now when you open this you see this button here and now when you click on it it shows the form all right guys for some reason I'm not able to set this to default open true I think it's because we have a trigger but that's okay what we're going to do here is we're just going to click on this and we're going to try to work with this right here so let's go into our workspace Creator now we can sort of see what we're doing so after this label go ahead and say div and give it a class name Flex justify center items Center and GAP two right here and inside this div we're going to return an input element which comes from UI input just like this and in here we're going to set the name to be name the value to be title let's also open this so we can see what we're doing awesome and let's change this to a closing tag actually I don't want it there and we're going to say placeholder equal to workspace name like this on change is going to have a function in here and it's going to be e okay and then we're going to set the title to um e. target. Val and after these two divs guys right here hit enter and create a react fragment and we're going to say label and inside this label we're going to have HTML 4 set to the uh permissions Like This Ss i o NS right permissions and um inside this we're going to have the class name which is going to be set to text- smm and uh text- muted D foreground like this okay and the lay table is going to say permissions like this so in here we should be able to see permissions awesome so the select component comes from Shaden UI so let's go to Shaden and let's search for select where is that right here so click on select scroll to the bottom click on this one again and go ahead quit this and paste and hit enter awesome now we can copy this these import statements and we can uh just paste it right up here and after this label guys right here we're going to use this select component so the select is going to have an an onv value change which is going to be a um a callback function that was going to give us the value and in here we're basically going to set permissions like this to our value and we're also going to have the default value to be set to the permissions and inside the select guys we're going to have the select trigger like this which is going to basically basally have a class name of width full height 26 and negative margin top of -3 and inside this trigger we're going to say select value just like this okay and we're just going to make a use it as a closed tag and after this trigger we're going to say select content inside this a select group and inside the group we're going to have the item and this item has to have the value and this first one is going to be private like this and um inside this we're going to basically kind of create that item okay so it's going to have a div with a class name of padding 2 Flex Gap 4 justify center items Center and inside this div guys we're going to have the lock icon which comes from Lucid react right here so just put that in here so I'm just going to go ahead and run end p.m run Dev so we can see the new changes and now when we click on that we should see this right here awesome check that out so after this lock we want to create another article like this with the following class names text- left flex and flex-all okay and inside this we're going to have two spans one span right here and another span right here okay actually this one can be a paragraph um let me see maybe we can just use this paragraph This should be fine and inside this we're just going to say private and I'm just going to paste some um some text in here feel free to do whatever you like um there we go like that so your workspace is private to you just like that guys awesome okay so you can hit the drop down and you can select another option too go ahead and try to take it up as Challenge and build another one for share and the icon you're going to use is share from Lucid react and if you don't don't know I'm going to show you exactly how to do it so hopefully you got it right if not I'm just going to show you what to do you want to do the same thing we just did which is have a select item with the value set to Shared you want to have a div with the same styling that we had as before right here and inside that we're just going to put the share icon and the article with the exact same styling but we're just going to change the text okay and now you can see we can just change this so this is going to allow us to change between a shared and a private workspace and also guys this is completely responsive as you can see on mobile it takes the full height and on desktop it takes half of it now after the select say uh permissions like this and um this is actually going to be after this react fragment right here we're going to say permissions so let's also expand this so we can actually see what it looks like all right so we're going to say permissions equal to equal to shared and we're going to return a div like this okay we're actually going to hold on to this because we're going to need another component but uh what we're going to do here is after everything guys right after this the uh this permission right here what we're going to do is we're going to return a button like this from UI button and we're going to say create in here just like that looks great and we're going to set the type to be button like this and disabled if there's no title or the permission so basically if the permission is shared we want to make sure that there are actually collaborators in there or else is there's no point okay if it's a shared workspace there has to be collaborators so we're going to say permissions equal to Shared shared and collaborators do length is equal to zero okay so if that is true we're going to set it to disabled right there and after this we're going to say variant is equal to secondary right after this to say onclick and this onclick is going to be create item which we haven't built so we're going to build that uh build that function in uh just a second so let's just say create item let's go up here and we're going to create const create item equal to a function and this is going to be an async function right here and this is basically going to say const unique or or like ID all right or uu ID is equal to UU ID and this is basically V4 so I'm just going to say V4 here invoke that and we're going to say if the user. ID exists then we're going to say const new workspace is going to uh is going to be workspace and we're going to say data set to so this is basically all the properties guys okay so I'm just going to copy paste this to save you guys a lot of time and basically the data is going to be null this uu ID is going to be right here um and we're going to have logo null workspace is going workspace owner is going to be this ID uh in trash is going to be empty title right here um the ID icon and so on so forth okay so next thing we're going to do is what is this error okay the banner URL is missing so let's set the banner URL equal to just an empty string for now if the permission is equal to private then we're going to basically await create workspace okay and this comes from queries we're going to create the workspace and we're going to say new workspace just like this and then we're going to say router. refresh just like this but if it is a shared workspace we're going to say permissions equal to Shared then we're going to return the following we're going to return await create workspace invoke this and pass in the new workspace and then we're going to say await add collaborator which we um have right here we're going to pass in the collaborators and the unique ID which is the uyu ID that we have right here and then we're going to say um router. refresh so this collaborator right here guys is actually from our queries it's not this ad collaborators right here so this is going to be add collaborators so let's go to our queries which is inside superbase queries and let's create that right here go to the bottom and you want to say export const add collaborator uh collaborators equal to async function we're going to invoke this and we're basically going to get the user which is set to user like this and we also need the workspace ID which is a string okay and in here we're going to say const response equal to users dot for um sorry um this is actually not going to be users user guys it's going to be users because we might want multiple collaborators right so you want to say users dot for each and then we're going to have async function like this okay and this is basically going to give us the user give this a type user and here we're basically going going to say const user exists okay so we're going to check if the user exists uh already in this if not there's no point in add it I mean if they're already there you can't add them again as a uh workspace collaborator right so we're going to say await dbquery do collaborators which we actually did we even create that let me see so let's go to this and let's actually close this right here and let's do npm run pull we might might need to make a quick change here cuz we're going to see some errors um okay in migrations we see some errors so let's go to our super base right here and let's go ahead and um copy this one right here subscriptions and you want to go back into our migrations and we have to update our subscriptions uh table right here okay this one just go ahead and replace that with this and you should be good to go so now in our query if we say query. collaborators it's going to be there okay so query. collaborators do find first so we're going to search for just one and we're going to check where we're going to say P or U for example we're going to say EQ and we're going to set this to equal so this is a condition guys right here okay we're going to say equal um before that we also need and so let's actually wrap this in and like this okay and we want to say equal u. userid is equal to the user. ID okay and also it should be equal to two things so we're going to say one more equal to u. workspace ID is equal to the workspace ID we just received okay so if we find that user we know the user exists so if no user exists only then are we going to do await db. insert collaborators do values and in here we're going to say create an object and say workspace ID and the user uh ID is going to be set to the user. ID okay just like this awesome so again I'm just going to go ahead and say npm run Dev like this let's close that and Let me refresh this page and here we're going to now import the ad collaborators action like this so now let's see what this looks like awesome so if it's private it needs the title if there's no title it's not going to work okay so that's why we did this and you see this is what it looks like on mobile device looks amazing so um awesome and if it's shared the title is not going to work either because we need to have our collaborator so let's go ahead and set that up okay so inside these this permission where we're saying share we need to return something else so right here guys we're going to show all the collaborators right here okay we're going to need another component too but um let's first go ahead and um actually let's go ahead and build out the component okay the component is called right in here we're going to call this collaborator okay collaborator like this U search so you want to go into your globals and you want to create a new file called collaborator Das search okay and um this is basically going to be rafc okay sorry we need to say TSX here and then just say rafc collaborator search like this have an interface right here so we're going to say collaborator search props and we're going to set it to the following so existing collaborator um actually this is going to be user this is also going to be a user and this is going to be react. react node just like this use this right in here so we're going to say um react. functional component and we're going to say collaborator search props and then we're going to also extracted from here so we're going to get children and then existing collaborators and get collaborators okay just like this and after this guys we're going to say const and we're going to create a search for the uh State for the search results so when we search for a collaborator we want to sort of keep track of the results that come right so um let's go ahead and say search results and set search results okay just like this now you know what to do this is a a client component so go up here and we want to say use client you want to say use State just like this user an array of users or it's just going to be an empty array aray so for now we're just going to pass in an empty array okay then we're going to create a timer ref guys and what this timer ref is needed for is basically we want to sort of like debal the results right we don't want to immediately on every single onchange fire a request that's going to be super expensive so we're going to say use ref like this and in here we're going to create a type called U return type and this one is going to be type of uh set timeout and this one can just be left like this for now and we're going to say const super base um actually we don't need this cuz now we have a new hook that we created user equal to super base uh user like this and we can get access to the user right here so I'm just going to create a use effect in here removing this timer here just to do a cleanup function oh sorry I put this inside the dependency array just put it in here and if the current exists then we're simply just going to clear the timeout okay that's it and then we want to say const on change uh Handler is equal to a function we'll get to this in a second and finally we want a const add collaborator all right so this is going to be a function too guys so what we're doing here when a search shows up on the screen when we look up some collaborators or some profiles we're going to get a bunch of users and then when we click add on one of those users we want to send this to the parent component that's uh using this collaborator search that way we can add that in the form right in here okay so when we click shared and then okay it's going to show an error but uh I'm just trying to show you what we're trying to do right when we add the collaborator that collaborator is going to come up into this component and then uh we're going to set it locally and that's how we can create the workspace so I'm just going to leave this blank for now and let's go ahead and create our uh search component so this search component component is going to need the help of sheet component from chat cnii so I'm going to cancel this go in here copy this the npm command paste it in here and let's just give it a second awesome guys so let's also copy this to kind of speed up our process and paste the import statements right up top here and let's change this to sheet okay and inside this we want to have the sheet trigger which is right here and the sheet trigger is going to have a class name of W-4 and we're going to get the children and put the children in here okay then we want to have the sheet content guys and the sheet content is going to have a class name of width of 400 pixels and from small devices we're going to set the width to 540 pixels okay and in here we want to have the sheet header like this set actually no class names for this and then the sheet title like this and in this title we're just going to say search collaborator just like this and in here we want to have the sheet description as well so this is going to be a paragraph tag and we're going to give this a class name text- small text- muted D foreground and inside this guys I'm just going to paste some string and all that's going to say is you can also remove collaborators after adding them from the settings tab so we're going to have more options later after the sheet header we want to create another div and set class name Flex justify center items Center Gap -2 empty -2 and then in here we're going to have the search component from Lucid react and then we're going to have the input from UI input right here this is going to be a closing tag actually so we don't have that yet but we'll get to that in a second okay and in here we want to have the name equal to name like this so let's go to shaten UI and let's get the scroll area from here and go ahead and just install that all right so um I kind of want to see what we're doing too so let's go in here and uh get access to this collaborator search and in here we need to pass in the existing collaborators which is equal um to the following okay so this we're going to set existing collaborators to collaborators like this and we also need the get collaborator which is going to be a function which is going to give us the user or the collabor cator basically and we're going to set add collaborat we're going to invoke this add collaborator and pass in the user this also needs children so in here we're going to add a button like this and give this a type of button class name of text- small mt-4 and then in this button we're going to have a plus like this which comes from Lucid react and then we also need add collaboration creators let's actually see what this looks like so if you do search there you go if you click that awesome guys it shows our search collaborator okay so there's a small problem here we'll go ahead and fix that yep we don't want this height to anymore in here so it's just automatic height okay awesome and also on mobile devices it's kind of shrinks like this looks great guys after this background color we want to set the placeholder equal to email and we want an onchange so an on change we're going to set that to on change Handler the one we created up top right here right there and we're going to do some stuff in there too okay so before that let's um create the scroll area with from from the UI scroll area guys and inside this first we're going to give this a class name of mt-6 overflow y scroll w- full rounded DMD and inside the scroll area going to go through the search result results. filter let's say if the user already added a collaborator we don't want that collaborator show up and we don't want thems to also show up okay so we're going to say filter um like this the result not existing collaborators do sum and in here we're going to say existing existing. ID is equal to equal to result. ID after this blue um bracket right here we're going to do another filter and we're going to say result result and we're going to set this to result. ID not equal to equal to user question mark. ID we want to do a map so we want to go across all of those and we're going to get the uh user like this because that's a collaborator return a div and this div is going to have a class name of p-4 flex justify Cent uh justify between and items Center awesome and then we also need a key right here so it's go ahead and say key equal to user. ID and inside this guys we're going to basically create another div and set the class name to be equal to flex Gap D4 items D Center okay and then now we need the Avatar class name width of eight height of eight and in here Avatar image and set the source to be equal to avatars like this 7.png Avatar AR fallback and inside this we are just going to say Cypress after this Avatar we want to have a div here have a class name text SM Gap 2 overflow hidden overflow ellipses withth 180 and text muted foreground and inside that we're going to say user. email okay so we're going to show the email of the user after the second div create a button here and this is going to have a variant set to secondary okay yeah we're not going to see that yet but um what we can do we can just pass in some uh fake values so we have an array and we need the email something gmail.com and then what else do we need so this is a user so we have a bunch of stuff to do we're just going to set this to partial for now like this we kind of see something here this is kind of messed up so we'll go ahead and fix that in a second all right guys okay so the reason why this is messed up is because this is flex right here and that yep that should fix it awesome and in this button to return um just add in here so when we click this button we want to say onclick like this is equal to add collaborator and pass in the user oh sorry actually this has to be uh like this remove this data and we're going to remove this partial so let's go up to this add collaborator and what we need to do in here user which is going to be of type user and in here we're going to say get collaborator and we're going to send in that user that we just created okay this is how we can pass the UI to the other component as well so our onchange Handler is going to do the following okay so this is going to be e so we're going to get an event here which is react. change event um like this and this is going to be an HTML input element and in here we're going to have if timer ref then we're going to clear timeout okay and we're going to say timer ref. current like this and if not then we're just going to say timer ref. current is equal to set timeout invoke that and this is going to take in a callback function with we're just going to put 450 milliseconds like this async const res equal to await head over to our queries file create export const get users from search like this is going to be equal to async function email which is going to be a string and we're going to check if there's no email we're just going to return an empty array const accounts equal to db. select like this from users. where I like okay like this from drizzle and this is basically um checking where the text is like so the email is like something and this is going to be users. email like this and in here we're going to use a string literal and say email and put a percentage symbol right at the end guys finally we just need to return the account uh accounts actually just like this go back to our component and let's import that so we want to say get users from search e. target. Val and then we're going to say set search results to whatever we get whatever we get from this response let's go ahead and quit this cuz we're making too many migration requests it's actually causing an error all right guys so let's head back to our workspace Creator file and after this collaborator search you want to create a div like this and give it the following style margin top of four and um okay let's close this div here and inside this you want to create another span and you want to give it some class names text- smm text- muted uh- foreground and what we're creating here guys is basically we're just going to display the collaborators that have been selected okay so when you click this uh from the sheet and you search up some collaborators we're going to basically populate that right here just say this right here which is collaborators right like this and collaborators do length or we're just going to return an empty string and then after the span we're going to to use the scroll area that we just installed and let's give it the following Styles height of 120 pixels overflow dy- scroll with- full rounded DMD border border Das muted foreground and um yeah you want to set it to 20 we're going to put all the collaborators in here collaborators do length if this is true then we're going to return something and then if not we're going to return something something else so if it is true we want to do collaborators do map like this and we're going to invoke this and we're going to get access to the collaborator so I'm just going to call it C like this and inside here I'm basically going to return a div just like this so first p-4 flex then justify between items Center t equal to C do ID and inside this we're going to create another DH Flex Gap D4 items D Center okay and inside this go ahead and use the Avatar and inside that one we need Avatar image and Avatar fallback say SRC equal to/ avatars sl7 um. PNG so we'll do some test data real quick so um and the Avatar fallback is just going to be I'm just going to put some strings right here and after this Avatar right here go ahead and create another div and set the class name to text- smm Gap D2 text- muted D foreground overflow Das hidden overflow Das ellipses from the small devices we want the width to be set to about 300 pixels with 140 pixels inside this div put the collaborator so C . email so when we click this right here and have shared uh we should see the email with the uh collaborator as well so let's quickly fix this button too and then we'll see what it looks like Okay so let's go ahead and say button like this and inside this we're going to say remove then let's set the variance on this to secondary onclick is going to be remove collaborator DC right here so let's go ahead and see what this looks like all right guys so you can do this too just go to chat GPT okay awesome so it went ahead and created that for us paste this in here and there you go guys you can scroll through all your collaborators so if I remove this if I if I click on James Smith is removed from the uh workspace just like that so right now we have this here when there are collaborators but when there are no collaborators we want to return something else right so we want to create a div and give it the following class name so we're going to say absolute right- 0 left d0 top -0 bottom d0 Flex justify center items Center so let's just create a span here give it um the following class names text- muted D foreground then text- smm and inside this we're just going to say you have no collaborators let's basically reset this so if we remove all the collaborators in here and just like that you see we have you have no collaborator so I see something wrong here so it's right here in the absolute like this and that's going to send it to the center so let's go ahead and see whether all this stuff works perfectly okay so I went ahead and just created some mock users in my authentications tab and you can do that by clicking on authentication and then this table will show up and uh for some reason if it doesn't show up make sure you have all users right here and then you can hit add user and then you can create cre a new user so don't send them the invitation cuz these are just mock users and go ahead and put the email and the password and make sure this is checked just to make sure our trigger function is actually working if you go to users you see every time we create a new user or they sign up with our application we're also populating this table change it to a shared workspace and then go ahead and hit add collaborators and then here we can look up like testing for example and there you go the two users that start with this text which is test showed up now now if I type in a lot of things back to back it's not going to send the API request because it's debounced that way it's performing let's try to add Joe as a workspace collaborator we're going to add him and he shows up right here inside the collaborators Tab and now we can also remove this collaborator from here so let's go ahead and hit remove and that's it and also the number showed here just to make sure this create button works if we don't have this name here we cannot hit create I just Tred to click it and now if we just set uh some sort of workspace here now we can go ahead and create this workspace call this shared workspace okay just to test it out make sure everything works all right so I want to also maintain some loading state so I'm going to say const um is loading and set is loading equal to use State and we're just going to say false in the beginning and uh we're going to set this um the set loading right here so we're going to set is loading to true because we started uh loading this right here the bottom after this is done so after the private workspace is completed um and this is also completed after these two things right in here we're going to uh set this to a set is loading to false we can just come in here and just say um this one or is loading and let's go ahead and hit create all right guys so it looked like it did create it but I had some sort of issue here so we're going to test this one more time just going to delete this and uh primary keys please add a primary key column to uh delete this okay so we need to create a primary key column here go into this schema right here and let's shrink this let's go into our collaborators table and we want to have an ID so we're just going to copy an ID from here just like this ID like this let's go to the bottom paste this ID in here default random primary okay this look looks good let's refresh this and run npm run generate and then run npm run Dev all right guys so something seems to be wrong here I'm not sure why this primary key is not being updated so what I'm going to do here is I'm just going to show you guys how to edit this from here okay click this drop down here on collaborators hit edit table go ahead and click this primary key right here and hit save we're going to go into our code and we're going to close this and say npm run pull so let's select all of these and let's go ahead and delete these two rows awesome after this we're going to use the toast const toast equal to use toast just like this after we create the workspace we're going to just invoke toast like here and then just say title success and we'll just give it a quick description and just say and we can do that after this as well let saying something here so oh okay guys so the issue is when we made the pull uh when we pulled we got this weird error again this is unfortunate we have to go back to our schema so let's uh replace that and that should solve our problem we are going to create first the private workspace so we're just going to say a private workspace and let's go ahead and create it awesome and let's just take a look at that awesome it shows up under the private worksspace so let's say a shared workspace like this and let's just add some collaborators because I cannot create it so we're going to do this and we're going to say Joe gmail.com and we're just going to have this person create the router. oh router. refresh has to be invoked right here so let's say if we refresh this page we're going to see a shared workspace okay and you can click on this workspace and you see the ID up top is also going to change um just like this go back into your sidebar. TSX file and what we're going to do is first just change this to a closing tag and we're going to create another component called plan usage and this component is just going to show the user how much have they consumed from um the current plan uh which is folders. length and we're going to say this is equal to the workspace folders data. length after that we also want to pass in the subscription okay because we want to show uh what the user has so we're going to pass in the subscription awesome there we go so let's go ahead and open your sidebar and inside that create a file called called plan- usage. TSX and we can do rafc plan usage so interface plan usage props so folders length is going to be a number just like this and we need subscription is going to be the following which is subscription or null so let's go ahead and import this from our superbase types now let's uh use it here so react. functional component plan usage props and then let's extract these values from here which is uh folders length and the subscription just like this so use clients and let's go back to our sidebar and now let's just import this just like this so what we can do here guys is instead of passing this we can just say um or length like this maybe zero there you go it's showing the plan usage component so let's go back to our component and let's create it right here so first thing we need is this is how this has to be a used client component because we're going to set some states but we're also going to set some default values from the server okay um so first thing we're going to get here is the workspace ID and the state and this actually comes from remember our app state right here so use App State just like this after this we're going to say usage percentage and that's going to be a use state so let's import it from react and we want to pass in some formula right here this is going to be the folders length divided by the max folders for the free plan import that and we want to divide this oh sorry multiply this by 100 let's create a use effect it's going to set the plan usage based on our local state as well cuz that can also update right inside this user effect I'm going to say con State folders length is equal to state. workspaces doind workspace where the workspace doid is equal to the current workspace ID that we're on and then we need to find the folders so we're going to do question mark folders. length just like this okay and then in here we're going to say if State folders length is uh equal to undefined we're just going to return and if not then we're going to set the usage say State folders length divided by Max folders free plan and um star 100 so the max folder free plan is I think think about three right all right three right there let's replace this with an article tag so we're going to say article like this give it the following class names which is margin bottom-4 and inside this we're going to set the following so we're going to say subscription question mark. status okay so if it's not equal to active then we're going to return something right in here only if the user is on a free plan we want to show this okay let's give this the following class names so go ahead and do this with me you want to say Flex justify between with full items Center and inside this we want to put another div and we're just going to say free plan and then we can create a small tag can say usage percentage. two fixed and we'll say zero in here and we'll just add the percentage sign right at the end by 100% to show how much we have used after this this tag here you want to say subscription. status and that's going to do the question mark okay is not equal to active then we want to send uh we want to return something else so we're going to return a progress component and this component comes from shaty and UI and let's copy this and paste this Command right in here and let that install let's first do npm run Dev come into this component and you want to say progress from UI progress guys not radics the value is going to be the usage percentage and the class name H1 if this number was for example 30 you see it populates all right guys so what we're going to do here actually I want to change this a little bit I want to basically create another div and give it the following class names Flex We need to put all of this inside this Gap -2 text- muted D foreground margin bottom of two items Center so now it kind of looks a little better right before this class name right here we want to create another div and give this the following class name height of four and width of four and what this is going to have is custom icon that we're going to set go to the GitHub and you can copy all the icons don't go ahead and start building these out okay just go ahead and copy them and paste them um in the folder I'm going to tell you right now go to Source go to components and create one right here called icons paste all the icons right in here guys okay so go ahead pause the video do that and come back to the video hopefully you managed to paste these and it's basically just an SVG these are from our figma file guys if you remember and we just changed a couple things so if you did if you did copy the SVG file from the figma file into this make sure you change the fill rule so by default it's the fill rule is going to be like this you want to change it to uh something like this and the same thing for the clip rule as well go back to our file and inside this div where we created this height and width for Cypress Diamond icon just like this now let's head back into our sidebar which is right here and we're going to have another component in here and this component is going to be called the native navigation component before that I just want to pass in something like this my workspace ID equal to pam. workspace ID so let's copy this native navigations go into the sidebar and you can say native dnation TSX and say RFC I paste that right in there awesome and the interface is basically this right here which is um my workspace ID is a string class name is a string and it's optional and get selected item which is a string uh which is a function that returns void and takes one parameter with the selection and this is optional as well go ahead and use this I'm going to say react. functional component navigation props like this and we're going to extract these values from here actually so we might not even need this gu so let's go ahead and remove this um yeah but you can have that in there if you ever wanted to pull the value out of this component okay so we're going to return a nav element like this with the class name of Tailwind merge and you want to pass in margin Y2 and then the class name that we just got in as a prop inside this you want to pass in a unordered list you want to have a bunch of list items inside this UL will give it a class name of Flex Flex column and our list item is going to have a link which comes from next link class name set to group SL navigation uh navigation actually go ahead and change this to not navigation but native Flex text- neutrals D7 like this transition Dall href to/ dashboard SL dollar sign my workspace ID okay so if you click on the first link it's going to take you to your workspace homepage go back into the sidebar and let's import this component we need to open this and inside here we need to show our link right so right now let's open this link and inside this link we're going to create home icon like this have a span my workspace in here awesome so now when you hover over this you see it does that that thing right there and in this link guys you can just say Gap -2 awesome that looks so much better okay so this is why we use those custom svgs so that we can use this hover animation all right we'll come to the uh rest of them in a second uh which is the settings and the trash but let's first go ahead and build out this part um right and then we'll come to that but for now what you can do is you can just duplicate this three times right here so we have a flex on this Flex column I'm just going to set gap of two in here as well to give it some spacing and we're going to change this one to set settings this is going to be Cypress settings icon just like this and this one is going to be trash and we're going to change this to Cypress trash icon let's go back to our sidebar after our native navigation let's create a scroll area like this class name overflow D scroll relative height 450 pixels open this like this and I'm going to say div just like this we're going to give it the following class names pointer events none withth full absolute bottom zero height 20 BG gradient to top uh from background to transparent z40 so what this is is basically like a gradient that sort of Fades into our navigations so the next component is going to be our drop- down list so we're going to say folders drop down list like this drop down list and it's going to be this component so let's go ahead and Al pass in the props right before we create that so we're going to say workspace folders is equal to workspace folder data workspace ID is equal to pam. workpace ID so depending on which workspace we are on we also going to fetch that let's go ahead and copy this and let's create this workspace folder which is basically the um folder Dash and then- list. TSX and rafc and you can just paste that in here what this is going to do is it's going to act like a container that's going to hold all our drop- down elements so in here we're going to do a couple things the first thing we need to do I'm just going to put some comments here and don't worry all the comments are also in the GitHub repository so okay we're seeing this error here so I'm just going to go ahead and import it so um we don't have that error anymore okay awesome and um what we're going to do in here the first thing is first we'll set some states right and uh we're going to also have uh keep track of our local States for the folders because we uh we also want to update it um you know automatically so we don't want to always refresh the entire thing we want to also use our local app state that we created so we're going to keep track of those local folders in here we're going to set its default to the workspace folders and then we're going to have a effect in here that's basically going to set the initial State okay based on the server data inside our app State okay and then we're going to also set our folders when the state changes and then we're going to have an add folder function right here to add a folder into our folder list and finally we're going to just return the components so let's go ahead and build out these States const state and dis patch is equal to use app State const folders and set folders like this equal to use State let's go up here and say use client just like this folders are just going to be workspace folders so what we get from the props so let's go ahead and just create the interface for that so the interface is going to be called folders drop-down list uh props like this and workspace folder is going to basically be of type folder and an array of that and the workspace ID is a string say workspace folders and the workspace ID just like this okay and let's use this here so react. functional component folders dropdown list props and one more thing we need to mention here is we need to set up realtime updates so basically when another user creates a folder we also want to have a realtime update system setup so that it can um create a folder for us in our local app State as well right so we're going to get to that uh right after we build this out and see what it looks like and then we'll get to these um realtime updates so right in here I'm just going to say work in progress for this one and work in progress for this one as well let's go ahead and create the use effect if the workspace folders exist so the length for this is greater than zero then we're going to do something so since we need the workspace folders we'll pass in here we're going to dispatch in you type um set folders all right so we want to say setor folders like this and let's go ahead and create this inside our reducer go to your Libs folder go to provider go to state provider and you want to create a new type here and with type set to set folders payload a workpace ID because we need to know where we're passing where we need to enter these folders and the folders which is is going to be an array or it can be the app folder type that we have up here an array of the app folder type just like this and let's go ahead and create this reducer for it so after this we're going to say case set folders is going to return an object with everything in the state but we want to have workspaces which is going to be state. workspaces do map the workpace if the workspace doid is equal to action. payload do workpace ID then we're going to do something if not we're just going to return the workspace just like this in here we're going to say return a new object with everything inside workspaces but we want to set folders to be the action. payload do folders um do folders like this and we oh so I made a mistake here so I'm going to change this to folders like this but we want to sort this so This callback function is going to give us a comma B new date invoke it and pass in a do the created at and. get time and invoke it like this so we're going to say new date a like this so what is this saying B.C created at so this is showing some error here so let me go ahead and fix this in a second all right guys so our created at has a string or null this is weird let me go into our schema and we need to kind of update the tables to have the default value set okay so let's go ahead and do that just give me one second all right guys so for created at after this after saying timestamp we want to say default now we want to invoke this and we also want to say not null and invoke this too so we did it for workspaces let's go ahead and do it for the folders too for the files as well right after this just like this and you want to save that um I think everything else is good to go okay let's go to the collaborators okay it already has it in here and then what we want to do here is run npm run generate and run npm run Dev and the workspaces have a timestamp okay let's see if we can pull this so we want to create another terminal here and just say npm run pull and get ready to change that right there go into our schema we need to copy our subscriptions because we're going to have that typescript error of update this to the new subscriptions okay awesome let's close this and we have another typescript error in our folder so yeah we need to pass our folders in here all right guys so go back into your file into your folders drop down list and after this type you want to set the payload to be equal to an object here with the workspace ID and finally the folders uh we're going to set it to an error uh sorry an array an empty array right now we're going to just say workspace folders. map we're going to go into all of these so why we're mapping over this and not just setting it is because we want to add an additional property to this and we're going to return a new object in here and this is going to be everything inside folder but the files are going to be set to state. workspaces do uh find okay so we're going to find the that specific workspace like this uh where the workspace doid is equal to our current workspace ID we want to check for the folders and we want to find those files from these folders okay so um so we'll just say F like this I guess and then we'll say f. ID is equal to folder. ID and then we want to get the files from this just like this and if there's nothing in here we want to make sure to set this to an empt array because it's going to be undefined and we can't do that so now we went ahead and set our local states to update that and in here we also need the workspace ID like this so let's pass that we want to also update our local States because we that's how we're managing the server data we're going to say set folders okay to the state. workspaces doind this returns us the workspace so we're going to say workspace doid is equal to workspace ID we need to get the folders from here so let's just say folders like this and if there's nothing in here we want to set it to an empty array uh the reason is because by default we want to use the workspace folders and then after that we want to use the folders that we have In Here Also let's provide state in here as a dependency cuz we're using State and let's go ahead and return a react fragment and then say div like this class name flex and we want to set this to Sticky z20 top zero background is a BG background W full height of 10 group title justify between item Center uh a padding right of four and text neutrals of eight so this one is actually text neutrals neutrals 8 go ahead and create a span this span is going to have the class name text neutrals 8 font bold and text is extra small and what is this so this is basically like a title okay it's like a title that's going to look exactly like this but when we scroll we're going to stick this to the top of the page so that we can scroll past the folders let's go to Shad CN UI and let's get the tool tip scroll here and just copy this tool tip and we're going to just paste it go into our globals folder and this component is going to be called tool tip component like this. TSX and it's going to basically be our wrapper for our tool tip okay because I don't want to have too many things inside um our jsx so we're just going to say interface tool tip component props and let's use that in here react. functional component and we're going to pass in the tool tip props and let's extract the children and the message return the tool tip provider make sure it's coming from UI um see so I made a mistake here so I'm going to go ahead and delete this and import it again from UI tool tip so we have the tool tip in here and inside this we want to have the tool tip trigger inside our trigger we're going to put all the children then the tool tip content which comes from UI tool tip again which is going to be the message and we can use this tool tip right here so we're going to say tool tip component from Global's component like this plus icon from Lucid react um also have a size of 16 and it's going to have a class name of group- hover /title inline-block hidden cursor Das pointer all right guys I want to touch on one of the errors that we were facing so far so basically you if you recollect in the um in the browser it was showing this error which uh said something like uh you know remaining connection slots are reserved for non-application super user connection turns out that the reason why this is happening is because we have too many open connections since we're doing this migrate stuff right here and communicating with the database okay so the way to solve this the temporary solution if you have this issue guys is basically to restart your database and what you could do is you can just uh click on this so um you can go to your database go into settings click on database right here and scroll to oh sorry go to General right here and then you want to scroll to where it says restart your project you can hit this one but this is going to shut it down for a couple minutes but I'm just I just use the fast database reboot so go ahead and click on that and that's hopefully going to spin up your project back and you're not going to have any issues again okay but um the more permanent solution which I suggest you guys look into is creating this connection Pooler in here instead of just uh creating this regular connection client so the way to do that is in drizzle they actually have the Pooler right here and you can just follow these instructions guys it's the same thing you see they create the DB here and you're exporting it and uh this pool is going to be the connection string and if you go into your database you can get that new connection pulling string uh from here so if you go into database uh you see you have a new uh connection pooling custom configuration string here okay so this is a string you want to use when you want to uh use this pooling configuration okay so um that's about it um I just wanted to point that out but for now just to you know keep the Simplicity of this video we're just going to restart it from here okay so go ahead and do this if you ever see that error on the screen and um that way it will res start your project and everything will work perfectly awesome all right and after this cursor pointer we want to say hover like this dark and uh we want to say text- white okay cool and this is basically the plus icon that I was talking about so let's go ahead and import this tool tip component that we just created and let's go ahead and pass in some props here which is the message is going to be create folder just like this okay so now guys when we hover over this folder right here it's going to show this but if we hover over this then it's going to show this tool tip okay and when we click on that we got to do something from there so we'll get to that in a second but uh basically this is what we want to get set up for now and then we will allow the user to create the folders okay so after that we are going to go ahead and create an onclick in here so we're going to say onclick like this is equal to an add folder uh Handler okay just like this and we're we're going to create this uh folder Handler so let's go on top right here and let's say const add folder folder Handler is equal to a function and this is going to be an async function okay check if the folders. length is greater than or equal to three okay we want to check if it's greater than or equal to three and we also want to make sure that there is no subscription okay and this is actually going to come um our basically our local provider that we created okay so we're going to say com uh subscription is equal to use superbase user just like this and this is going to retrieve the subscription for us so if there's no subscription and the folder's length is greater than or equal to three then we're going to do something what are we going to do here guys we're basically going to um open uh like a model on the screen okay and this model is we're going to get to this in a second but basically this model is for the pricing okay but let's work on the pricing stuff towards the end so we're just going to hide this for now and what we're going to do here is we're going to say const new folder um equal to an object and this is going to be of type folder like this and this object is going to have data set to null and then a folder ID folder ID like this we're just going to set this to uh uu ID okay so we're going to create a uu ID right here and this uu ID is basically V4 so I'm just going to to import that real quick and invoke it awesome and then we're going to say created at is set to a new date ISO string uh and you want to invoke this like this and the title is going to be Untitled because it's a new folder so okay guys this is going to be called ID sorry about that not folder ID and then here icon ID is going to be uh a page okay and you can just open your emojis if you're on MacBook it's uh the FN key if you double click that or single click it's going to show that and you can just click on a page or you can just copy this from the GitHub repository okay and then after that we want to set intr is uh equal to null and finally the workspace ID okay and then we also um actually yeah we also need one more thing which is the banner URL and this is going to be an empty string okay and after that we're going to say dispatch so we're going to dispatch an action what is this action guys this is adding a folder to our local States so um I see here something is wrong it's saying new folder but it's values never use case logo is missing so the logo for the folder is actually not needed so let me go ahead and look at this folder right here and in folders okay so there we made a small Arrow here we have an extra logo column which we don't need because logos are only for our workspaces right so let's go ahead and remove this logo from here so from folders and we can remove it from the files too just like this and um we want to go ahead and search for what else workspaces that can stay and then let's remove this and uh we can say npm run generate like this and we can do npm run Dev and we can refresh this page okay and that's going to go ahead and migrate our changes all right awesome so that was successfully migrated so let's shut that down and uh let's go back to our code so basically we need to dispatch something to our uh to our local state which is the type called add folder which we don't have right now so we're going to do that in a second and um our payload that we're going to pass in here is what we're going to use inside our reducer to set that so let's go ahead and go to our Libs providers State provider and you want to scroll up to the types here and take this up as a challenge and go ahead and try to create a type here with a payload with the folder in there okay just take it up as a challenge to create this that way you're actually doing some work all right guys so if you haven't already this is what you have to do don't worry about it if you didn't get it right this is what you got to do okay so create an object here under the types and you want to say add folder and you want to have the payload set to the workspace ID because we need to know what workspace to add the folder to and the folder here is basically going to be the folder itself okay so let's go down to our reducer right here and also guys you can just reduce code by just using the set folders that itself right here instead of doing this you can basically set something to an array and put everything that's inside the folders by default and then you can put in the new folders that come in from the payload you can do that too but I want you guys to practice okay this is the only way to get better which is to type more and to write redundant code I know that sucks but that's the only way to get better okay so go ahead and just type this with me and let's see if we can um you know get this correct okay so um hopefully you got it right but if you didn't this is what you got to do so first you want to return everything inside state but then you want to set the works uh the workspaces to be state. workspaces do map just like this so workspaces do map and this will give us access to the workspace and then we want to basically return something here so we're going to return uh an object with everything inside the workspace okay but we're going to set the folders to everything that's in workspace do folders like this but the new um thing is going to be passed in here which is action. payload do folder like this so the new folder that we passed into the payload is what we're going to add to this array and at the end we want to say sort and uh this gives us uh we have to pass in a callback function and say a comma B and it's the same thing guys literally the same thing that we did before uh which is the new dat minus uh the new created ad and the old um and the the prev previous created at okay so we're just going to say new date A.C created at uh. getet time minus the new date B created at. get time okay so it's just going to also kind of kind of um you know sort that out for us okay so let's go back in here and now we need to pass in the this payload so we're going to say payload is equal to um this right here but now we need to pass in the workspace ID so we'll say workspace ID but the folder is going to be an object with everything inside the new folder right here so I'm just going to put that in here but we want to set the files to be equal to an array okay because this is what our new folder structure requires okay and after we do this we're going to say await create folder which comes from our queries which we're going to create in just a second and we're going to pass in the new folder just like this all right guys awesome so let's go ahead and create this so head over to your queries which is inside super base query like this and you want to go down here and just uh maybe go up to where we say add right here yep and we're going to say export const um create yep so let's just say create folder which is equal to an async function just like this and we'll give this async name right here and this function is going to taken a folder so we're going to say folder is of type folder from um which is already imported so that's good and in here we're going to say const results or response yeah is equal to await db. insert into folders okay do values and folder like this okay and of course you want to wrap this in a TR catch so let's bring this up in here and we want to uh check for this and if there's any error right if some error occurred here we're going to do something so right here we're going to say um return and object so we're going to return just an object with data set to null and the error set to null right here and if not uh what we're going to do because we don't really need any data here but we're just doing this for the error uh error handling right here so we're going to do return return right here too in the catch and for error we're going to set this to string um error like this if some error occurred and let's also console.log the error in here okay awesome and now let's go back to our code and uh what we need to do in here is let's go back in here closes queries and let's import this okay and this gives us access to data so we'll take const data equal to this one and we also want to say error like this okay and this new folder this is wrong so it's new folder and we want to check guys if error exists so if there was some error for some reason we don't need to actually put a TR catch in here because we're already handling the error there and just returning that so we're going to check if there is an er error then we're going to say toast so let's go up here and make sure we import so const toast equal use toast not theme sorry use toast like this and we want to go to the bottom here and we want to basically set this toast okay so we're going to say toast invoke this and we're just going to pass in the title and say error and then we can just say variant equal to destructive and we can give it some description and say could not create the folder just like this okay and if it was successful then we're just going to uh return this so we're going to say else and we're going to return this toast but we're going to say created folder Okay so we'll say success no variant right here and then created folder like this awesome and um this should be it so um yep I think this should work let's go ahead and we can probably give it a shot and see what happens uh but we're not going to see our folders here yet because we haven't rendered out our folders right so um yeah but let's see if this function even works first um so basically what we're going to do is we're going to add a folder we're going to create this new folder we need Title icon ID just like this okay cool so if you go ahead and hit this right here this created you see this got UPG updated right here because we have used two folders but let's see if this request was successful so let's go into our database go into tables and then let's just give this a second to spin up and then click on folders and there you go guys it success sucessfully created our folders and linked everything that we needed in here okay perfect so I'm just going to go ahead actually we can keep it in here no problem and uh now we need to actually render out these folders right here okay all right guys so we're going to go ahead and build this folder these folders right here which is basically a bunch of accordians put together okay and we need to also set the default path name and all that kind of stuff so let's get to that in just a second but before that we need to go to um shaty Nui and we need to install this accordion component so let's go in here and search for accordion which should be up top just like this and let's uh scroll to this and copy this npm command and let's come here and let's quit this and paste it in here okay and let that install awesome cool now that we're done with that uh we can go ahead and build our accordion so we're going to say accordion like this from UI accordion and this accordion is going to to have the following properties so uh first thing we need is um let's say a type so type is equal to multiple and um we also need to pass in a couple other which is the default value because by default if the user is on one of the pages right we want to get the folder ID from there and we want to show the folder um we want to show we want to open that folder ID right so that's why we need this default value and this default value we can actually get from um the folder ID that is open correct so let me see here all right so we're just going to go up here and say folder ID from the use App State and uh we're going to go down here all the way to the bottom and we're going to set um okay so the default value right here we're just going to set it to this array with folder ID in here or it's just going to be an empty string because it's default value for some reason uh needs to take this right here okay and um that's about it enter and just give this a class name and um the class name is going to be padding bottom of 20 like this okay we're going to do a couple things so first we're going to do folders. filter so we want to only render out folders that are not in the trash can okay we want to show everything that is active so we want to say folder here where folder not folder . intr okay and then we want to say map and we want to get the folder here and then we for each of this we're just going to return a div for now this and let's just save that and this will need a key so let's provide folder. ID just like this okay we'll get back to this in just a second but um let me go ahead and spin up our server again so npm run Dev and let's refresh this all right so now we're going to build a very complex component because this is going to have all right guys a small problem here here so what we did is we put this accordion inside this div go ahead and bring it right outside that um and if you ever saw this create folder getting indented that's the reason why okay so that should do the job there so yeah inside this we're basically going to create um a new component and this component right here is basically going to be a drop down components a little complex uh component that does a bunch of stuff but we're going to go ahead and build this okay so go ahead and open your sidebar and create a drop-down okay just say drop down. TSX like this and say R fce awesome great job and this dropdown is going to have a couple things so what this dropdown is for is basically to show the um the the drop down itself like a folder or to show it like a file okay so first let's go ahead and provide the interface and and um the interface for this is drop- down props with the title set to string the ID set to string the list type is going to either be a folder um a file or native okay actually we're not even going to use this native so we'll remove it for now if we need it we'll bring it back okay folder or file and then we need the icon ID here and we need the children to be react. react node and disabled to be a Boolean and uh the custom icon to be um react react node again okay so let's also go ahead and extract that from these uh from the props right here so we're going to say react. functional component and let's pass in the drop- down props and uh finally let's just extract all of this from here title ID list type icon ID children disabled custom icon and everything inside the props right here great job we're going to basically create a superbase client right here and then uh we also need a couple other things Okay so so let's first just kind of get an overview of what we need to do so first we want to have a folder title okay that is synced server data and local data so this has to be synced okay and then we're we need to have the file title too because we're going to use the same component for everything and um after that we need to also have a function to navigate the user to a different page okay like this and then we want to have um a way to add a file so when they click on a drop- down like at the end like you see we have this right here if they click on it we're going to be we should be able to create a file just like that okay and um after that we also want to have the ability edit those um files itself or or the folder also so that is made possible with a double click so we're going to just say a doubleclick Handler so if you double click this for example you'll be able to change it okay and uh we also want to have a blur so when the user clicks outside it we want to save um you know the the user's new updated title for the folder or the file and then we also want to have the an some a bunch of on changes okay so I'm just going to say uh on changes right here and then also the Emoji change and move to trash so when the user deletes this we want to First add it to trash we don't want to immediately deleted okay so um let's go ahead and say move to trash so we have the move to trash in here and then uh we're going to do a couple other things like getting some styling and so on so forth and then we're going to return the accordion item okay pH that was a lot of stuff but um I hope you guys are still with me because if you are you are truly going to learn a lot in this project all right guys awesome so let's go up here first and just say const superbase is equal to create create client component client like this and then we want to say const State dispatch maybe we'll get the workspace ID it comes from the use App State and then after this we want to say is editing okay and this is what we're going to do to basically allow the user to uh edit the titles is editing like this is going to be equal to use State and this is going to be false by default and then uh finally we need the router to to help uh route the user so use router and um then we need const path name okay path name is going to be equal to use path name actually I don't think we need this let's see if we do but this has to be a client component of course CU we have so many states in here so we're going to say client use client up top and we'll come to the path name in a second okay I don't think we need that right away so let's go in here and create the folder title syncing so we're going to say con folder title so before we build all this logic we want to see what our components even look like right so first let's go ahead and build this component and as we go we're going to build a logic for it so first we need the accordian item which is which comes from UI accordion and inside this we're going to say value equal um ID which comes from our props and then we have to say class name is equal to um a some specific class name Style that is right here so we're going to say list Styles and we're going to create this in just a second so this list Styles right here is going to be const list Styles and you can just put this in a use memo if you'd like use memo and this is going to be equal to something here um and in here we need to pass um some other properties um to basically help make this work but we're going to import clsx like this and we're going to set this to relative okay but this object is going to say the following so what it's going to say in here and don't worry we're going to have this error in here but we're going to fix this in just a second okay so border none is set to text MD and Border none here and but with margin left text -16 and padding y of one this is only if the following is a folder if it's not a folder then we want to do this okay how do we determine that is basically by saying is folder equal to list type um equal to type of folder okay that's it you can just use this right here or you can just do it directly in here if you don't want to no problem okay awesome guys and you want to pass in the is folder right in here like this great job okay basically now we have the new list style so for a folder it's going to be something else and for a a file it's going to be something else and and um now let's go back to our accordion right here and we want to also say onclick so when we click this we want to do the following this is going to be an arrow function and this Arrow function is going to do a couple things so the first thing we want is to stop the propagation okay so we're going to say e do stop propagation like this because it's going to go up the chain because we're also going to have child elements in here and we don't want that to send it up so we're going to say e. stop propagation and then we're going to create a new function called okay navigate page ID and have the list type right in here okay just like this great job so let's go ahead and build this function navigate the user to a different page so con navigate page is going to be equal to a function that's going to take in the accordion ID okay so we're just going to say accordian um ID like this which is going to be a string and the type is going to be a string as well okay and in here what we're going to do is we're going to check so basically let's also bring in this folder ID right here okay and we'll have the accordian ID right here so no problem so what we're going to say here is if type is equal to folder then we're going to do something and if not we're going to just render another one here and we're just going to say if it's equal to file then we're going to do something else okay and then here guys what we're going to do is we're going to say router. push and we're going to push the user to a stringing literal just like this we're going to say dashboard okay and um in here we're just going to say dollar sign like this and we're going to say the workspace ID that they actually have selected and slash um dollar sign accordian ID right here okay because it's a folder all right and um for the file what we can do here is we can just say um con file um actually we already have this folder in here so here if it's uh a fold a file we're basically going to say router. push the workspace ID slash we also need the folder ID so we're going to say folder ID slash the accordion ID okay so that way we go to that file just like this great job and then let's go back down to our code right here and then let's move on in inside this we're going to have an accordion trigger which comes from UI accordion and this is going to have ID equal to the list type this is basically going to have a class name that is going to be set to the following so it's going to have a class name with hover set to no underline uh padding to dark text- muted Das foreground and text is going to be small okay and after that we also want to have a disabled property and this is going to be disabled if the list type is equal to file okay and um right after this we're going to have a div inside here we're going to say class name and this is going to be another class name guys and this is going to be called group identifies okay so let's go up here and let's create this group identifies right here which is called const is equal to um just a um uh clsx like this and again you can use memo if you'd like for this too no problem I'm just going to put it in here and I'm just going to say the following so dark text white um wh space no wrap Flex justify between items center with full and relative okay and the second parameter is going to be an object that's going to have um group Das folder and we're going to set this to is folder if it is a folder then we're going to use this style if not then we're going to use another style which is group slash file and this is going to be set to if it is not a folder like this okay so now now we have a bunch of different options right here so we're going to pass that inside this div guys now we're going to create another div here and say class name equal to um uh the following okay we're going to say Flex uh Gap 4 items Center justify Center and then overflow hidden okay and inside this we're going to do some conditional rendering which is going to say if the list type is equal to um a all right so I just realized we're actually not going to use this custom icon I think so what we can do guys is we can go ahead and just remove this custom icon just like this okay um all awesome that should fix our problem and um in here we're basically going to do some conditional rendering okay so we're going to say if the list list type is equal actually we don't even need to do this because for all the list types we we need to show this Emoji picker right here okay we're going to say div we're going to say div and then we're going to give it a class name of relative like this and inside this we're going to use our new Emoji picker from our Global uh Emoji picker okay not the one from the package and then we're going to say get value and we're going to pass a onchange so we're going to say on change Emoji Handler like this and let's go ahead and build this out right here but before that we're just going to pass in the children to which is icon ID just like this and let's go up here um and create this on change and this on change is actually pretty simple so let's go to the on changes and say const is equal to a function here like this and this is going to be an async function and we're going to get the selected Emoji which is going to be a string and in here we're going to say const path um actually we already do have the path for the folder all right so in here we're just going to say if the list type is equal to a folder okay then we're going to do the following we're basically going to dispatch something in here which is going to dat our folder with the latest information okay so we'll just do this in a second but right after this we want to also uh create the API request to save this right here okay so let's go ahead and do this what I'm going to do is I'm first going to work on the reducer so let's go into State provider and I want you guys to take this up as a challenge again and try to build this on your own okay and this action is going to be called update folder okay all right so hopefully you got it right but this is what you got to do type update folder and uh you want to set the payload to folder of app folders type and the workspace ID okay so let's go to the bottom here and you want to say case um and this case is going to be update folder just like this and this is basically going to return a new object with um with everything that is inside State and uh but we want to set the workspaces to to be state. workspaces do map everything inside the workspace so we're going to get the workspace from here and we're going to um basically check if the workspace doid is equal to to the action. payload do workspace ID okay if it is equal to then we're going to do something if not we're just going to return the workspace right here so if it is then we're going to basically set it to the following so we're going to return a new object with everything inside workspace but the folders are going to be set to workspace do folders. map like this which gives us access to the folder and we're going to say um the following if the folder. ID is equal to the action. payload do folder ID so right now now what we need is uh we're going to get the new folder right okay let's go up here we also need the folder ID yep that's right guys sorry in this action we also need the folder ID which is going to be a string so let's go back here to the bottom and we're going to say action. payload do folder ID just like this and if that is true then we're going to do something if not we're just going to go ahead and return the folder itself so without any mutation and in here we're going to return a new new folder okay which is going to look like this but we're going to use the spread operator on the action. payload do folder like this so this way you can reuse this for almost anything for setting the Emojis for setting the titles uh you don't have to have like a 100 different actions like update folder Title Update folder emoji and things like that okay awesome great stuff so let's go back to our code and let's dispatch that action right here so let's go in here and say dispatch like this dispatch let's invoke this and let's pass in the type which is going to be update a folder and the payload is going to be the following which is first the workspace ID and this also needs the folder ID so we're just going to say folder um ID but actually this folder needs to be different so we're just going to say the folder ID that comes in from here right so we need to say ID like this so we'll say folder ID is going to be the ID and um so what is this issue it's saying it's not assignable okay so we want to make sure there is a folder of course so we're going to say if folder um if ID exists only then we can do this oh sorry guys this is actually folder ID just like this let me see is this actually okay that works I thought that was the issue my bad so this workspace ID is undefined so this is the one that we need so we're going to say if workspace ID has to exist so we can just put that up top so if no workspace ID we're just going to return so that should work and then we also need the folder um that we want to pass in here so this is going to be an object with everything um that is inside this folder um which we're uh actually we don't need that we're just going to set um this like this and we're going to say emoji and we're just going to set the icon ID to be equal to the selected Emoji just like this and uh let's see what's the issue here um it's saying it's not assignable to type app folders type okay so we also need to set the folder to everything in here but um this I think is just an error guys so what we need to do here is it's okay I know what the problem was so I know what the problem is you want to go back into your state provider and right here we said it has to be of type folder which is an issue here right because it can be anything in here so we want to say partial like this and then we want to pass in this app type right in here and let's import partial like this okay now that's going to solve our problem because we want to partially update it or sometimes even fully update it it's up to us and finally let's go ahead and create a query under this so go into queries and we want to create uh we want to do an update folder right here so uh what we're going to do here guys is we're going to create a export const update date folder equal to async async and U this is a function like this and we want the folder which is going to also be partial folder like this and let's go ahead and import this from partial and um in here we basically want to say const response equal to a weit actually we don't even need a response we're just going to say a weit actually actually sorry we're going to say try catch and in here we're going to say await db. um update uh invoke this folders. set and we're going to just pass in all of these values so we're going to say pass in the we're going to pass in the folder itself and um after that we also want to say where um the folder ID so in here we have the folder and we need the folder ID which is going to be a string so we want to say where equal to um folders. ID and folder ID just like this okay so only for this folder ID we want to go ahead and update the folder to this one okay awesome now let's go ahead and return an object with data set to null and um error like this set to n in here and also if there was an error then we want to return this so we want to say error error and let's also console.log the error for us to see what was wrong so error like this awesome guys great job so let's go back and use this update folder action right in here so after this dispatch you want to go ahead and say await update folder invoke this and and you need to pass in the newly updated folder so first one is going to be I think a string a first one is the folder itself so we're going to basically create an object here and we're going to say icon ID is going to be selected emoji and the folder ID is just going to be passed in like this so This ID here is the folder ID like this okay awesome and um this okay sorry this ID has to be the second parameter not part of that object awesome guys so we're going to also check this so we're going to say const data and error like this and um we're going to set this to equal to this if there an error exists then we're going to use toast which is which we're going to get in a second and we're going to set the title to error and um variant to uh okay actually let's go ahead and do this I'm not getting typescript right here so we're going to say const toast equal equal to use toast like this and let's invoke this and let's go to the bottom cool and we want to say variant equal to destructive and then the description is going to be a bunch of stuff so could not update the emoji for this folder okay just like this and that's about it all right and um yep and we can also put else so something like this and we can just say else here so there's no error we're going to create a success success and we're going to say updated folder Emoji so update updated Emoji for the folder okay just like this awesome so there we go guys now we have this setup so let's move on to the next part which is um let me see what do we have left okay so we have this accordion trigger um with the folder in here Emoji picker in here sorry and after this Emoji picker we need to do a couple of things so after this Emoji picker guys we're actually going to have an input component okay and this input component is going to allow us to do a couple things okay so first thing we're just going to use the regular input because um the custom input from from the shatti UI has too many styling stuff on it so we're going to say type equal to text we're going to say Val value equal to um list type if the list type is equal to folder then we want to return the folder title okay which we're going to get to in a second or title like this or the file title just like this of course we don't have this but we're going to we're going to create it in a second and uh let's go ahead and just create this class name too right here and this class name is going to basically um just be the following so you can use CLX right here but I'm I'm just not going to use clsx right now but um basically we're going to say outline none overflow hidden the width is going to be 140 pixels and text is going to be uh neutrals so this is going to say something like this neutral 7even just like this awesome and then we're going to have this is editing so if the user is editing this then we want the background to be muted okay and then the cursor to um have text and the cursor pointer if that's not the case if they're not editing so let's go ahead and first create the folder title and the file title okay so the folder title is um let's see where do we have that right up here okay so we're going to say const folder title is going to be equal to actually it's going to be a use memo hook let's make sure we import this awesome we imported it and this is going to be just like this and in here we're going to have States and list type okay so State and the list type right here and what we are going to do here is we're going to set this to string or undefined just like this and in here we need to return this so we're going to say if list type is equal to folder then we're going to say const State title equal to state. workspaces doind okay doind we're going to find the workspace where um just like this like this where the workspace doid D is equal to the workspace ID that we're on right now okay the workspace ID and actually let's pass in the workspace ID in here too and if that's the case then we're going to get the folders from that so we're going to say folders just like this and we are going to find the folder where folder. ID is equal to the ID that we have up top okay so we're going to also make sure that there's an ID in here if ever this is never going to change but we're just going to have this in here okay and then we're going to get the title from this awesome guys so this now has that value so we're going to check if the title is equal to the State title so if this the say if it's the same title that we already had from the server or if there's no State title then we're just going to return this uh title here okay return title or we're going to return the State title then we just created right here okay so it's kind of like alternating between those States all right awesome well title and this is actually not going to change because the server is going to pre-render with this data so it's already going to have the title and the state but okay we'll just put it in here it's not going to cause any harm okay um then after that let's go ahead and create the same thing for the file title so equal to a use memo and this is also going to have the same return type so I'm going to say string or undefined just like this this is basically going to say if the list type is equal to file so in this file ID guys what we're going to do is it's actually going to be a combination of the folder ID and the file ID okay and uh because of that we actually need to extract it from here we're going to set it later but uh I'm just giving you guys a heads up that's why we're doing this part right here which is const file and folder ID right just like this is going to be equal to the ID do spit so we're going to split this with the folder okay I'll show you what this is going to look like in a second just just bear with me okay and if you don't know what's going on it's fine guys just keep working you're going to understand eventually okay so we want to say State title now is equal to and I'm going to say the following right here which is um this state. workspaces right find the workspace where the workspace ID is equal to the workspace ID we're on then we want to get the folders from there we want to check for the folder where the folder ID sorry this is ID like this is equal to the file and folder ID at zero and then we're going to get the files from that and then we're going to find the file where the file ID is equal to the uh file and folder ID at one and then we're going to return this title right here okay and once we get this guys we're going to do this quick check here which is we're going to check if the title is equal to the State title or there's no State title and then we're going to return this new uh the title that we have initially or we're just going to return the State title awesome guys now we can pass in some dependencies in here which is basically the state the list type right in here and uh we'll also need the workspace actually we don't even need this but we're just going to pass it workspace ID and um what else do we need we need the ID in here and we'll also pass in the title sure okay awesome great job now let's go to the bottom and let's continue and see what else do we need so we also need the is editing so the is editing is actually going to come from um a state okay so let's go up top and say const is editing right here here okay sorry guys I made a spelling error here so this is going to be 1D and this one up here is actually going to be 1D all right so I only made it right here so now this editing is going to work and this file title is also probably incorrect somewhere so file title is going to return this string um but here it's having some issues okay it needs just a capital letter okay sounds good so so far we have these but what else do we need let's see so we need to set the is editing as well um we'll do that in just a second but that's going to come from a click so um in this in this input then we're just going to create a uh read only which is going to say equal to not is editing just like this and then we're going to say on double click this is going to be a handle double click that we're going to create so we're going to say handle double click right here and let's go up here and then let's just create this handle double click right here so const equal to this which is going to be a function and what this is going to do guys is it's basically going to set the is editing to true so we're going to set is editing to True right here and then we also want to have an on blur function on our input so I'm just going to go here and we're going to say on blur is equal to handle blur okay so I'm going to go up here and I'm going to say const handle blur equal to a function like this okay I'm going to go down here and just update this too okay and in this handle blur what we're going to do is we're basically going to set it okay we're going to update it so let's make this an async function because uh we need to save the user data now and uh what we're going to do is we're going to set is editing first to false like this and then we're going to say const of folder ID so or we'll just say uh yeah F ID like this equal to ID dosit and this comes from the folder okay so um this ID uh comes from basically when we're passing in those custom IDs right um and we'll get to that in a second all right and then right here we want to say if the folder id. length is equal to 1 then we want to basically check if the folder title does not exist okay if not we're just going to return here or we're going to update the folder again okay so we're going to to say update folder and this needs the updated folder which is basically going to be uh let me see so this one and then the folder ID so we're going to create this and we're going to say title is going to be just title and finally we need to pass in the folder ID which is going to be the F ID right just like this okay so this is saying um argument of type strings okay this is going to return us an array that's right so what we want to do here is we want to say at zero sorry about that guys and after this we want to check if it if it is a file okay so if it's a file we're going to say if the folder id. length which is basically this F id. length if this is equal to two so even here guys this is going to be FID sorry sorry about this F id. length and this FID do um length is equal to two and we also want to check if the FID at one exists then we're going to check if there is no file title if there is no file title we're just going to return and if not we're going to say update title file okay but we'll come to this in a second we haven't worked this yet so I'm just going to say work in progress update the file just like this okay cool great stuff guys and after this we also have to have an onchange and this on change is going to change the title only locally okay so let's go back into the input field right here and we're going to have an onchange Handler which is going to say if list type is equal to folder then we're going to do something like this or we're going to do something like this okay and um this one is basically going to have the folder title change and this one is going to be the file title change okay let's go ahead and create these right now so where are where are the on changes right here so after this Emoji we're going to do const folder title change equal to Something in here and then const file title change is equal to um a function um just like this okay and what this is going to do in folder title title change is we're going to get e which is a Target and we're just going to set this to any for now now and then we're just going to do const the FID equal to ID dosit at folder like this and uh we want to check if the F uh if the F id. length is equal to one and if it is equal to one then we want to dispatch something okay we're going to dispatch the type set to update folder and this is going to have a payload and the payload is going to have um basically uh let's see what is it going to have in here it's going to basically just have the title this is going to have the folder set to something and then it's going to have the folder ID set to something and then it's going to have the workspace ID set to something okay so um let's fill these in so the folder is basically going to be an um an object with a title like this and this folder ID is U going to be the f ID that we just created right here F ID like this at zero and then the workspace ID um is basically just going to be the workspace ID like this so we don't need to do anything in here so okay this needs to bee present so we're going to say if workspace ID does not exist just return out of this okay great job and after this we're going to also create the file on change all right now for the file on change we're going to have e again we'll just set this to any like this and in here we want to say const like this FID is equal to id. spits folder just like this and then here we want to check if the F id. length is equal to 2 and FID at 1 exist okay we need to make sure there is some ID in there and if so then we're going to dispatch something to basically update the file but we'll come to this in a second as well so we'll just say workspace oh sorry work in progress update file change okay update file title and um let's go down here and um let's check what else do we need right here okay this is good so after this input we have a div right here right so let's first of all change this to a closing tag after this we're going to check if the list type is equal to folder and is editing and and we want to return something right here okay so what is this part for so this is basically the trash icons and the add a new folder icon okay so only if it is a folder we're going to return this uh trash component if not we go we're not going to do that right so that's what we're going to do here so the first thing we want to have in here guys is actually a div that uh kind of um wraps all of this and we're going to have a class name set to height uh- full we're going to say hidden by default and then we're going to say group slash uh Das hover SL file like this file and then we're going to say block and then rounded is going to be- smm and then we're going to set this to Absolute and then we need write zero write zero items Center Gap to justify Center just like this okay and um inside this we're basically going to have all these things so this is for a list type folder okay so basically the trash icon is going to be in here but um okay so in here if it's a folder then we want to return this um special component right here which is a u um a add a file component so we're going to just put that in here so just give me one second so let's remove this fragment and let's paste this so now let's bring in our tool tip component and we're going to say add a file and the plus icon comes from Lucid react and we're going to add a new file okay let's just mute this for now now and um then we're also going to have the trash icon so the delete icon is going to be there for everything right um it's going to be there for everything right here so uh what I'm going to do right here is after this I'm just going to paste this and say trash icon from Lucid react delete folder and let's go ahead and create this um this ad right here so let's turn this off and we'll do this in just a second okay great job job now um let me also see if yeah so what we're going to say here is basically for this trash is going to be hover dark text white dark text neutral 7 and trans transition colors and the same thing for the other one too guys okay I hope that makes sense and um let's move on now all right so I think this is pretty much what we need to sort of at least see some folders so let's go in here to where we are rendering yep so where we are rendering the folders and we need to just return this new dropdown that we created okay so let's remove this and say dropdown from do/ dropdown and we're going to do this and we're going to say key equal to folder. ID like this um and then we need to pass in a couple others which is basically the title equal to folder. tile like this and then we also need to pass in the list type which is equal to folder for this one and then we need the ID which is since this is a folder it's going to have a different type of ID so we're just going to say folder. folder ID do ID sorry like this and then here we're going to say icon ID is equal to folder do icon ID like this okay so let's refresh this and see what happens awesome so we see this already it's some sort of hydration error so let me see how I can fix this hydration error all right guys so the um the hydration error was happening because of the Shad CN UI accordion component okay so inside the UI folder go to your accordion and I just had to make some quick changes inside this uh component to make it work okay so um I also put some notes Here guys and this will be inside the um inside the GitHub repository so you can get this if you'd like to but I'll just show you what I did so basically we changed this we put the children uh here and we said justify between items center right here and then uh basically we removed this Flex from this so um what we did here was we said according primitive trigger ref is equal to ref and the class name here is going to be CN with the following so um it's going to have these so Flex items Center let's put a space here too sorry about that um and Let me refresh this okay no issue there so items Center justify between the padding Y is going to be for font medium transition all hover underline and this thing right here I think this is for the SVG icon that you know kind of uh grows and shrinks like this so um go ahead and do that right here you can copy this and we want to also pass in the class name and then all the other props and then also the disabled right here so if there's not if it's if uh disabled is not true right then we want to show the Chevron so if we set it to disabled we're not going to see this Chevron so we just move this Chevron outside this into this trigger okay and pass it like this and U I think it this pretty much has the same thing the same animations so you should be fine okay so that was the issue guys um that took me a while to find but hopefully you guys got that and um you don't see this error anymore if you do see any errors guys don't worry the Discord is in the description go ahead click on the Discord and just ask away everyone is going to come and help you okay awesome so now there is also this ugly thing here I don't like this and I want to change this so um how do we change this so basically there is this color setting so um the color on this is kind of incorrect so here we're saying if not is editing then um maybe all right guys so the issue is because we were not using clsx and I totally forgot about that um you're going to have some uh discrepancies when you're trying to create it um just by using these um optional strings okay so go ahead and say clsx and pass the first string in here okay and then create an object as a second parameter right here and then you simply want to say BG muted cursor text to is editing and BG transparent to cursor pointer just like this and is editing is not editing right here okay so um what we're also going to do is we're going to shrink this right here okay so I see one typescript error here okay actually I know why because this could be an empty array right okay awesome so let's go into our um into our app folder right here and into main into workspaces and inside here create another folder called a folder ID just like this and um in here you want to basically create a page. TSX okay and I'm just going to return ra fce and we're going to say folder page like this and let's just return this so now when we click on this guys here you go you see it it uh switches to the folder page and if you click here it switches to the workspace now if you double click this now you can go ahead and update this title right in here okay so let's see if this works actually um we're going to make a change okay this is not changing so I think there might be we're not actually setting the local state so let's go ahead and take a look at that all right guys so the reason why this is not changing in here the folder is not changing is because we set the title to the title we're receiving okay it has to be e. target. Val so e. Target um like this doal like this and it's probably going to be the same thing for the file too um do we even have that okay we don't have that set up let's see hopefully this works if not I'm going to be sad awesome guys so let's refresh this and there you go it also updates on the server how cool is this right look at that great and now you can click on this and you can also change this to for example a globe emoji and it immediately changes and now when we refreshed the page you see it also saved on the server and this is the reason why we had this um this default State here and we swap to the local state because if you refresh you see there's no loading it immediately shows these folders and does not take any time to kind of load these folders right and now you see this right here guys this is also open by default because we're trying to access this specific folder name okay so that's why it's open by default or else it would be shrink it would be shrunk like this so if we go back to workspace and if we refresh this you see it's not going to open here awesome great stuff guys let's move on to building the files now I'm really sorry I was recording and for for some reason my uh screen recorder crashed and I wasn't turns out I wasn't recording so I'm just going to um hopefully touch on the topics that um you know um I went across already and don't worry guys we're going to go across every single thing okay so I think we stopped here which was U the issue is when you hover over this this was not showing okay and the reason is because we were not using clsx and I totally forgot so what you want to do is you want to copy that first line okay that first line you have in there you want to copy that and you want to paste it as the first parameter in clsx and then you want to create an object here and you want to say BG muted cursor text um to is editing and this BG transparent and cursor pointer is if it is not editing and is editing I don't know if I've already done that but it's just a state here that has um you know set is set to false by default okay so that's the first step right there and after that we have this readon set to is edited Ting so if it's not is editing then um this is going to be um you know the value for this and on double click we're going to have a doubleclick Handler on blur a hand a blur Handler and then we're going to have an on change so for the on change right here if you click on this um I think we already solved that bug which was happening because we were not setting the value okay it's supposed to be e. target. value uh right in here so if you go to the onchange Handler which is right here you see we need to set the title to e. target. Val okay and the same thing is going to be done for the files as well so let's go down here and uh basically uh for the double click handlers I'm just going to show you what this is doing it's just going to set it set the editing to True okay and just follow follow with me guys all right just go ahead pause the video and keep doing it with me okay and then the um double click is going to uh set the editing to true and the on blur is going to do the following so first we're going to to check if we are editing okay if we are not editing then we're going to return all right so because we want to be checked into this before we actually fire this API request so then we're going to say const file ID equal to ID dosit at folder so if I didn't explain this already the reason is because for files we're going to create a special type of ID okay and this ID is going to have um like the file and the folder combined into each other if you don't know what that means don't worry about it I'm going to show you in just a second just move past this uh step right here okay so we're going to say if the FID so this is going to return an array here an array of strings we're going to check the length of it of the array if it's one then we want to check if we have a folder title okay if we have if we don't have a folder title we're just going to return uh but if we have one um then we're just going to uh create this toast saying the folder title was changed and then we're just being a little optimistic here and then we're going to create this update folder um uh action right here okay and if I haven't shown you this or for some reason I missed this basically it's a function here it's an async function and it takes in a folder which is a partial type of the folder and the folder ID and all we're doing guys is we're just making a db. update folders and we're going to set the folder where the folder ID right is equal to the folder ID that we pass in okay sounds good nice and here we're just returning data with null and error with null and if there is some sort of error we're printing the error and we're just returning this error okay so let's go back to the code now and that's what we're doing here because the first ID is going to be that folder ID okay so we're going to send that in here and then um yeah basically we're going to update this in the database okay uh in our tables then um next here this is for the files so we're still yet to work on the files but I already went ahead and created the files part but don't worry about it I'm going to show you what's what happened there so in here we're also going to have an on change okay and um I hope you guys made this work to which is just the folder title change and the file title change and if you look at this the folder title change is going to say if there's no workspace we're going to return and uh basically we're again we're splitting that ID and we're checking the length if it's one then we're going to dispatch this uh saying updated folder um updated folder title just like this okay and the folder title only changes um when we do the on blur basically so that's why we're not sending the API request right here and same thing will be done for the file title change as well so let's scroll back down right here don't worry about all that crazy stuff I'll just show you what we did okay and in here guys we created another component saying div like this and we said tool tip component for delete folder so if you go in here you can delete the folder like this so if you hit delete it's going to go ahead and delete it but we haven't built that yet and um after that we said if the list type is of type folder and we are not editing then we're going to return this U this component right here and basically what this is going to do is it's going to allow us to uh create a file okay so the onclick here if you go to the on click it's an it's an add a new file async function that basically checks if we have the workspace ID and if we don't it's going to return then we're creating an object called file here and this file is going to have the following properties okay the folder ID set to ID the data set to null created at set to the new date. 2 ISO string intr set to null title set to Untitled because it's a new file icon ID set to this and we're just going to do V for and workspace ID right here okay so there was one error with the file and the problem was in our migration schemas in here for some reason we didn't have that file um that we had that logo for the files okay so go ahead and delete that files it was something like this it was like this logo and something so just delete that logo from here and um actually not from here you want to go to your schema which is inside your Libs folder inside your super base schema and go ahead and remove that logo from the files table which should be somewhere around here all right guys remove that uh open your terminal and you want to type in npm run generate and then do npm um run Dev and then you can just refresh the page okay and that should actually fix that typescript error and right after that what we did is we went into superbase and we also updated our superbase types so we went here clicked on API we scroll to the bottom we clicked on generate and download types and then a file showed up okay open that file copy all the data in that file then go to your superbase types right in here under your superbase folder and replace everything above so you see this right here right above this all the way up top but right before our import statement so still this Json right here okay delete it and just replace it with that new data okay and um also to update your schema from this file you you have to open this and do npm run pull okay that's going to get the latest information from um our database that's it all right that's all you need to do to solve those issues so let's go back to what we were editing right here so after we create this new file we're going to dispatch a new ad file uh action okay and we built this ad file action but you can go ahead and take it up as a challenge but don't worry I'm going to show you how to do that in just a second okay so let's go to our state provider which is right here here and in our state provider if you go up top we have an add a file right here okay so this is just an action that says type add file with the payload set to workspace ID string the file which is of type file and the folder ID which is going to be of type string okay so if we go to this action all it does is basically first we say case add file and we say return an object so we're going to return an object by default and then we're going to say everything state but the workspaces are going to be set to state. workspaces do map and then we're going to get that workspace and we're going to set that to if the workspace ID was equal to the workspace ID we sent okay if that's the case then we're going to do something if not we're just going to return the workspace itself okay and then in here where we're returning a new type of workspace we're going to say everything that is currently in the workspace but we want to set its folders to something else which is a workspace do folders. map so we're creating a new folders a new list of folders here and we're returning that okay and then we're going to check in here and say if folder ID is equal to what we passed in in the payload right then we're going to do something if not we're just going to return the uh folder itself and in this new uh folder that we're returning we're going to put everything else that's in this folder but we're just going to go back to this add file right here and this is going to be set to files okay and um that is going to be a new array okay of everything that was in this folder. files and then we're going to pass in the new file that we want to add and do the same sort guys the same sort that we did for setting the file um for for everything else setting the workspace adding a folder the same sort we're going to do in there okay so once you're done with that that's how we do this part now let's go back in here and after this action uh after dispatching this action we're going to go ahead and do a create file action right here so let's go into this create action uh create file action and basically what it is is it's just an async function like this with a file set to this file type of file and then we're going to do a try catch and we're going to do uh db. insert files. values and we're just going to pass in this file okay if there's an error we're going to send this and if no error we're just going to send the data to null and error to null as well okay we actually don't even need this but this is just to do some error checking for us so in here we're going to check if there was an error if there was an error we're going to return a toast saying error destructive for the variant and description is going to be could not create a file okay else we're going to we're going to send another toast with a success message and the description set to this okay pretty simple right this is all you have to do to add a file so now the file is going to be added to our you know folders right there and now when you come down here let's see what we have here awesome so hopefully I did go across this if not guys don't worry everything is in the GitHub repository just go and copy paste it okay another problem that you might see right here is the color of the um icons are actually weird that was because I had it neutrals like this so make sure you update this color to whatever name you have okay so neutrals SL neutrals D7 okay if you remember the figma video that we built uh that we designed it's the same thing okay but just a different color name right here awesome guys and right right after this trigger you want to say accordian content so just build an accordion content right here and inside this we're going to say let me first explain what this is this is basically the files for our folders so let's go into this and let's take a look at what that looks like so if we had um files for folders right here I'm going to refresh this and you'll see we have a file right here right so let's open this and you see the file looks awesome awesome right so basically this file is what we are trying to render inside this accordion content okay so we're going to look across the workspaces state. workspaces we're going to find the workspace where the workspace ID is equal to this one right which comes from uh workspace ID which comes from our app State and then we're going to get the folders we're going to find the folder that we're looking for which is the folder ID equal to the ID of this you know this compon which is the folder ID and then we're going to say get the files from there but filter them out we want to filter them out where the file is not equal to trash is not equal to in trash so if I if I for some reason deleted this file it will be filtered out so this file will immediately disappear from here okay and uh then we're going to map over this okay we're going to map over that result and we're going to create a custom field ID so if you remember up here right up here we did const FID equal to .split this folder we did something like this right I hope you remember so basically for the file we're creating a special type of ID okay and this ID is required to set the default value for this uh for this file okay so that way we can we can tell which one is clicked and things like that so you want to come in here and say custom file ID equal to a string literal and first we're going to pass in this ID and then the folder and then the file ID itself okay I hope that makes sense and after that we're going to return a dropdown and pass in its props which is the file ID is a key title is file. tile list type is going to be a file of course the ID is going to be custom file ID which is this one we created and the icon ID is going to be the file. ion ID and let's scroll up I think I also edited this onchange Emoji so basically when the onchange is uh fired so if we change something here if we change this Emoji to a house for example it immediately changes and it gives me a success message so the way that happens is we are just checking for the error if there's no error we're going to just send um this one right here a toast with success updated Emoji for the folder and right here we're going to also check send a toast if there was an error okay it's simple stuff guys if you don't know if you're lost I promise you just go to the GitHub repository everything is in there just copy this section and I really really apologize if I missed something out guys please let me know in the comment section and I will definitely uh address you in the Discord and help you guys out okay sounds good um awesome and let me see if I missed anything else um I think that's pretty much it um for this hover Styles I think I already told you guys what to do right let me see okay so there was something in here okay what I did was I created a class here called hover Styles so let's go up top and the hover Styles is basically a use memo the same thing clsx and it has um this H full hidden rounded SM absolute right zero item Center and justify Center and now we're saying group hover file block okay and this is only true if the list type is a file and hover folder block is only true if it is a folder and that's why when you were hovering over it you couldn't see anything okay so that's all you had to do guys um I hope that helped I'm really really sorry for what I did and I will try my best to make sure my uh my screen recorder doesn't crash on me again okay uh thanks for being patient and now let's move on to the files okay if you have any questions uh please put it in the comment section all right so now we're just going to work on the folder title change and the file title change okay so let's uh move into that function so we have the file title change right here and what we're going to do guys it's very simple okay we're only changing this locally very similar to this folder okay so let's get in here so I have this work in progress flag here that's why it was really helpful so we're just going to remove this and we're going to um do the following so we're going to check the length and make sure it's two and we want to make sure the FID has an element at one if so we're just going to say dispatch like this and we're going to create a new action in here okay this action is called update file and in here we're also going to pass in the payload and this payload is going to take in uh our files basically so we're going to say file which is going to be some object here with um the title set to e. Target do in here value like this what we're going to do is we're also going to to set the folder ID and the workspace ID and file ID is going to be FID so FID like this at one okay cuz zero the first one is going to be the folder and the second element is going to be the file ID itself right so this is what we have to do so let's go ahead and go to our state provider and let's uh create the update file action okay so we have this right here update folder so I'm just going to duplicate this right below like this and I'm going to change this to update file and the payload is going to be the following so let me just copy this stuff file folder ID workspace and file ID so file folder so file of type file folder ID which is going to be of type string okay remove this workspace ID so this is going to be a string to right here okay so we need the file the folder ID the workspace ID and the file ID to edit okay and let's go ahead and copy this and we're going to um do the following so after this add file guys go uh down right here is we're going to say case update file is going to return an empty object with everything in state but we're going to set the workspaces to be equal to state. workspaces doind and we're going to get the workspace here and we're going to say where workspace is equal to the workspace we get from the payload right so if the works space. ID is equal to action. payload do workspace ID just like this so if this is true we're going to do something if not we're just going to return the workspace just like this okay so here we're going to return an object with everything in workspace so we're going to do a map here and uh then we're going to do this all right so um we're going to return everything in workspace but we're going to set the folders to be equal to um the workspace do folders like this map again because we have to return a new um set of folders and we're going to get access to the folder here and we're going to say if the folder. ID is equal to action. payload doid fi uh do folder ID like this and if that's true we're going to do something if not we're just going to return the folder just like this so in here we're going to return everything inside the folder but we want to set the files to be equal to something okay so this files is basically going to be um folder. files. map and then we're going to say file where um if file. ID is equal to the action. payload do file ID then we're going to do something if not we're going to do something else you guys are already experts right now you already know what to do so we're just going to return the file just like this but if not we're going to return a new object with everything that is in file but we want to um set action. payload do file like this but here's one one problem I see uh let's go back up to this action here this file is set to um a absolute file but we want it to be a partial file because we can edit any part of it right so do this and now this file can be anything in here okay okay so let's go back down and make sure everything looks good okay let's go back here and so this can be undefined of course we need to make a quick check so if no workspace ID then return right but we also want to make sure there's no there is a folder ID so no folder ID then we also want to return here and I think this should work all right awesome and what you want to do guys is you want to open your folders you want to go into Source app Main dashboard workspace folder and then in here you want to also create a dynamic ID for uh a dynamic route for this one okay so just say file ID so create a new folder in here and say file ID like this and then create a page. TSX and just return this for now okay this is so that we don't see a 404 not found or something like that so let's close this and go back in here and I think this is pretty much all we have to do to change the file locally but we also need to um do something right here so let me just take a look all right so this is the handle blur so what this is guys is basically when um when the user clicks out of our file we want to go ahead and also save it right that's when we're actually saving so in here we want to say await update file like this and we're going to say uh we're going to pass in the new uh file which is going to be an object with the title equal to um the file title right because it's updated in the state and the second parameter is going to be the ID which is the F ID at um one because it's the second one okay so of course we don't have all of this so let's go to our actions so I'm just going to click this so it's going to take me here and then I'm going to say export const update file equal to an arrow function like this and this is going to say async which is going to take in the file which is of type partial file like this and this is also going to take in the file ID which is a string like this um try and catch like this and in here we're going to say const response equal await db. update um like this dot um so we have to update the files so I'm going to put that in here do set and this is basically all the properties right so we're just going to pass in this file that we get in from the uh param right here parameter right here and then we're going to say um right here ass sets. where equal the files. ID is equal to the file ID that we passed in okay just like this awesome so if this is done we're just going to return and if there's no error of course then only we're going to return this data set to null and error set to null like this if not then we're going to copy this paste it here but here we're going to return this as an error like this okay just say error and you guys already know the drill we're just going to say console.log error so we know what the hell just happened in the server and we're not clueless okay awesome let's just close this file it's going to take us back let's import this and um FID is saying okay so there's an error here it's FID like this awesome so now we have basically created the on submit uh the on blur for the input fields for our files too okay so you see we made a quick change there now the reason the reason why we are fetching only when the user opens this is because it's um we're trying to make it a little more optimized okay or else if we first uh you know fetch all the folders and then fetch all the files that's going to take a little longer than if we just fetched only the folders we're only fetching the files when this URL changes so what we're going to do for this right I'm not sure if I mentioned it in the previous um section I'm really sorry if I missed that but basically if you go into our into your app state so go into Libs providers go into State provider let's shrink this again and you want to scroll down and basically this use effect which we had a work in progress we're going to remove this now and this use effect is what allows us to fetch this like this so when we refresh the page it's going to fetch it and also when we click this right it's going to fetch the files because this URL is going to change so let me show you that in action so you see if I click this it changed like that right so that's what we want so immediately when it's clicked it's already fetched so what we're doing here is we're passing the folder ID and the workspace ID as a dependency okay and these two of course Come From the Path name which comes from the URL and then we're saying if there's no folder ID or there's no workspace ID return don't do anything or we're just going to create a function here and invoke it and this is an async function that's going to Simply get the files okay it's going to do the same thing guys take this up as a challenge this is a server action just like what we built right now but don't worry I'll show you what to do in just a second so go ahead pause this and come back to this video after you're done all right if you couldn't do it this is how you got to do it okay so you're going to say get files and what this looks like is basically the same thing guys it's just a function that takes in a folder ID because you need to get the files for a specific folder and then we're going to check here if it is valid if this folder ID is valid um then we're going to um basically do this but if not we're going to return data set to null and error set to error okay and then we're going to use a TR catch here to basically get those files for that folder we're going to say cons results equal to await db. select. from files. order by files. created at where equal to files. folder ID and then um where the the folder ID that we pass in okay and we're going to return that as a file of an array of this file type or just an empty array and we're going to return this data if nothing happened but if an error happened you know the drill right we're just going to do that so let's close this and that's exactly what we did here so we simply just rename this to files error and we said if the error exists just console.log we don't want to do anything crazy on the screen screen okay we're just going to print the message out um but then if there's no data also we want to just return don't do anything crazy and for example this one right here see there's nothing in here so we don't want to do anything crazy right that's why we did that and then we're going to dispatch something to the store so if we have the data okay if data exists for this then we're going to set it that's why when you refresh this you see um let's open this folder and now let's refresh this you see it populates the reason is because we have some data here so now we're going to set files like this payload with the workspace ID and the files are going to be set to the data with the folder ID so if you want to know what this looks like let's go to the state provider right here and let's scroll above right up top and this action just takes a payload with a workspace ID which is a string the files set to an array of a file and then the folder ID is a string again so let's go back to the reducer now and the reducer is doing this it's basically returning everything in this state but we're going to set the workspaces to a state. workspaces do map so we're creating a new set of workspaces um and if the workspace ID is the workspace ID that we um that we're trying to edit which is this one then we're going to do something here if not we're just going to return the uh workspace itself and then we're going to return a new one like I said but we're going to pass in everything that's in the workspace we don't want to touch anything there but the folders is what we want to mess with so we're going to say folders are going to be equal to a new set of folders okay but if only if the folder ID is equal to the folder ID we want to mess with then we're going to return something else if not just return the uh the default folders okay and then we're going to set the folders to um everything that's inside that folder but the files are going to be set to the app action. payload do files that's it guys so let's go down here and just that's literally what we did here we got the data from this response uh from our action and we just set the data in this file that's it okay pretty simple so that's how it's doing this automatic fetching right here so let's go ahead and close this and go back to our handled blur continue from here okay so now if I click on this here and I change this title it's going to change it here but if I replace this it's already updated that is why we actually just uh mutated this only locally but on blur is what we set to save this in the database okay so we can do the same thing here we can just copy this toast and we can check for any errors okay so we can say const this will return um this will return data and error like this and we can check in here guys we can just say if an error exists like this if error then we'll return something so we'll just return something here else we'll just return this toast so I'm just going to copy one of the error toasts here which is this one let's go back up and U yeah right here so if there's an error say destructive could not update the title for this file just like this so if I click on this and update this to new type of file and hit enter boom boom there you go it says success so let's change that to file title change let's refresh that one more time and we're going to say um something like new change and click out that's it guys done awesome how cool is that and also this is responsive you see it shows the message at the bottom so you can swipe across it awesome cool guys great job so let's move on to the next part of this application now all right so now I went back into the folder drop-down component inside the sidebar and I just wanted to show you guys what we did here so we just commented this out because this is a work in progress and this is for subscriptions okay just so to show a subscription model on the page okay because the user can only create three cuz now if I create one more I'm able to create multiple so let's go ahead and just build a bunch of these and I wanted to just show you this cool fade in effect that we created right here look at that looks awesome right of course there's nothing in here but you see this cool fade effect that's what we built guys that's literally what we were building um right here okay so um that's just what I wanted to show you and now of course all of these are independent so let's go ahead and try to delete these folders now okay pretty simple so let's go back in here and let's scroll up to our delete uh Delete Handler which is this move to trash so how this feature works is when a user tries to delete a folder or a file it actually does not completely uh immediately delete it okay it sends it to trash and how it sends it to trash is just by setting the text in trash to some sort of a string like in trash just like that okay so um and we're going to sort of U change that uh text to have something in it so that we can show on the screen okay sounds good pretty simple right so let's go ahead and build this function out um so let's remove this and remove our flag here and let's go up top and create our on um to trash uh thing right here so move to trash I'm going to say const move to trash is equal to a function and this function is also going to be an async function like this and in here guys we're going to say const um the user actually we do have the user I think right we do have the user up top uh okay we can get it from const user equal use superbase user like this so now we have the user in here and I'll tell you why we need the user the reason uh why we need the user is when a user deletes the file we want to save their name um as like a metadata and show that on the screen on the message that said this user deleted this file so you can go and do whatever you want to do to them I'm just kidding okay not that all right so let's just say const um path ID okay equal to ID dosit um at folder like this okay and then also guys I want to just give you a really quick tip here you don't have to follow this method in specific because our relation if you go to our database right in here you can see that we actually have those files and folders all saved together so if you go into file you you will see the folder ID right uh let's see where okay workspace ID and the folder ID so you don't have to do it like this there's so many ways to do it I'm just giving you guys um the quickest way that I'm doing right now okay so we're going to get this path ID right here and then we're going to say if the list type is equal to type of folder then we need to do something right we need to delete that folder so we're going to dispatch this like this and we're going to say type is update folder so let's go where's our update folder update folder like this and the payload is going to be equal to our object with the um what do we need here we need the folder itself and the folder itself is going to have the intr property set to you know something like um deleted let's just say let's just create a string literal and say deleted by this user. um email okay right here user. email like this and of course we need this email to exist here so we're going to say if the um if no user then just return okay if no user. email that would be fine so we're going to say folder is going to be this let me go into our update folder action inside our inside where is that it's our app state which is in here inside library inside the providers State provider and let's go ahead and look for our update folder so we have it set to update like this okay H so okay we have our folders set to this all right well we did set it to partial so let me see all right guys let me try to see what the issue is here okay all right guys there was no error I don't know what the hell just happened but basically um we didn't have to do anything okay so after this all you're going to say is folder ID is the path ID and the workspace ID is this so this is how we can update that specific folder all right so let's go ahead and refresh this and run npm run Dev like this and reboot the server and um yeah this is how we can send it to trash but only locally so let's see if um we can make this work and then uh we will come back so right here if I come in here and delete this boom there you go it's gone but if I refresh it of course it's going to come back and the reason is because I haven't deleted it from the server right from from our database so what we're going to do here is we're going to say await up send um or actually we can just say update folder we can use this one and I think this is an async Okay cool so it requires the folder itself so the folder the first one is going to be in trash and we're going to set it to this message right here copy paste deleted by this user and um after this the second parameter is uh got to be the uh the folder ID right so the folder ID right here is simply just going to be this right here okay so let's just say path ID at zero just like this okay and of course we can get access to the stuff here we can say data and error like this and we can check if there is an error then we want to do something else we want to do something else and go ahead and just copy and paste um the other toast okay so I'm just going to copy this toast right here and I'm going to come down here and I'm just going to paste this right here and for this I'm just going to say if error exists error could not uh move the folder to to to trash like this and um same thing here success we're just going to say moved folder to trash like this so we just pushed it to trash and um let me see what else do we need to do right here of course guys you can see it we're being extremely optimistic here so this is not the best way because we are first changing the folders and then we're updating the data you might want to do this later if you don't want to be optimistic but we're just going to be a little optimistic here okay why not and same thing for the file guys so we're going to go down here and we're going to basically after this purple one we're going to say if the list type is equal to file then we're going to do a couple things here so what we're going to do is we're just going to copy this dispatch and we're just going to paste it down here but here we're going to say update file and we're going to have payload errors so we're going to going to say folder ID actually we already have the folder ID let's set this to file and this this file should be so let's say folder ID workspace ID and file ID is basically going to be the path ID but not at zero at one okay so we're going to say path ID at one okay yeah I don't know why it's showing the error for file it should show it for payload right that's really weird anyway and uh same thing here we're just going to update the file instead of the folder and we're going to say in trash deleted by this person and you can also put more things in here like folder deleted by or file deleted by no problem and in here we're going to update this ID at number one not path at zero and um the error yeah again we're just going to check the error let's make sure okay I have this query in here too awesome cool so now this should work guys so if I come in here and delete this folder and I refresh the page actually we're not going to know until we delete everything so I'm just going to delete multiple moved folder to trash and I and I refresh all these folders are actually added to trash now so if I come into my database and look into the folders table and let's look for the folder here um where is that yep and if I look here I see the intr set to deleted by um and my email is put in here so this way I can show it on the screen for another user when I'm using real time uh you know database when I'm using the realtime feature to show that this is what happened to this um to this file okay so awesome so far so good I'm so glad you're actually doing this because now we're going to learn so much from this okay so let's move on to the next part now all right so I want to just quickly test our file to so if we add a file boom there you go the file is added it says successfully created a file let's re refresh that and make sure our file is there awesome and if I go ahead and delete this file Boom the file is deleted but it's only added to trash and of course it's going to be add in the database because I just refreshed the page and I don't see that file anymore okay awesome great job so now what we need to do is we're going to move on to um the the fun part which is showing our um our components for the file workspace and you know our folder as well all right awesome now we're able to change between our different workspaces here but for some reason we cannot edit them right we can only create a new workspace but we don't want this we want to be able to also edit that and that's what we uh do from the settings option so when the user clicks the settings tab a settings uh modal pops up and then we can go ahead and edit all the settings of this workspace so let's go ahead and do that now so go to your native navigations compon component right here under your sidebar and uh right here we have the um dashboard for our Cypress setting icon yep right here we just have to do a couple things right here okay we're going to change this link we're no longer going to use a link here uh but we're just going to use a list element so um what we can do is we can just change this guys just to An Li and delete this list element okay and of course we don't need hre because we're not um navigating routing the user to a different page or anything okay so it's going to be the same exact styling but we're going to have this right here so there's no cursor so we can have cursor set to cursor pointer like this cursor Das pointer so now you know it kind of shows the cursor like that awesome so what you want to do now is you want to wrap this entire thing in a custom component that we're going to create called settings okay um just say settings like this and don't import it from Lucid react because we clearly don't have this component yet and pass this in here and what we're going to do is we're going to go ahead and create the settings component so go to your um sidebar right here and um after this in this component you want to create a component here called a folder here called settings um like this and inside that a settings. TSX and then finally uh we're going to go in here and say ra a fce and we're going to change this to settings like this okay and what is this going to do well this is basically our custom dialogue trigger that we created before okay we're just going to use that so first thing we need here is an interface so we're going to say interface settings props is an object here which is uh with children set to react. react node like this and we're going to copy this and paste it in here so react. functional component sorry not this it's react. functional component uh like this and open this and get the children from here okay and then all you're going to do in here is you're going to return our custom dialogue component which is our custom dialogue trigger like this from Global custom components and this is going to have a header set to the settings like this and we want the content to be equal to another component so for now I'm just going to set this to uh like a react fragment and in here it needs the children so we're going to pass our children components in here and this is basically a new component here called settings- form. TSX we're going to say ra fce and we're going to change this to settings form okay and what this is going to do is it's going to show the form on the screen so let's go in here and import this component so we're going to say settings formed oh we said settings forms here okay so let's change this we just wanted to say form um like this right here and this has to be a component of course just like that so let's go back to our setting form and we're going to change the all instances of this to just form like this and let's also import our settings like this from settings SL settings all right great job hopefully that solves our error okay nice so if we click on it it shows our custom dialogue trigger and this is also responsive automatically okay great job guys so let's go ahead and um get this to work so in this settings form we're going to do a bunch of stuff okay because we need to be able to edit the the workspace title the uh users information such as only the Avatar and then they can also set up their billing stuff and there's a lot of things that we need need to do in here so let's go ahead and start so first thing we need is first um is the const state actually let's get toast cuz we're going to use this a lot equal to use toast like this and invoke it and this has to be a use client component because of this and then we want to say cons State workspace ID and dispatch we need these three from the use App State and in here we're going to say const permission because we we also want to be able to remove collaborators add collaborators change permissions and so many so so much other stuff right so set permissions like this so I like it like this equal to use State import this set to private like this okay by default and we're going to say const so this array is going to be collaborators collaborators and set collaborators like this this is going to be equal to a use state like this set to um an empty array but right now we want to say it's yeah an array of users or it's going to be an empty array just like this let me shrink this so you guys can see the screen sorry about that guys and then we're going to also get our user so this comes from const user equal to use superbase user like this and then we want to get the router because we want to reroute the user sometimes so we're going to say const router equal to use router oh sorry guys use router that comes from use nav from next navigation and then we are going to put these on top so all these um hooks are going to be put up top and then we're going to create a couple more States so we also need a superbase client oh yep we need the client because we need to get the image the URL for the Avatar okay so that's why we need this so I'm going to go up here and just say const superbase equal to create client component client invoke it like this and we're going to also get some alert messages okay and we're going to create a state here for our alert message and this alert message is basically when the user tries to change the permissions of the workspace from shared to private we want to let the user know hey are you sure you want to do this right so let's go ahead and set this to uh open alert message like this and we're going to say set open like this alert message equal to use State invoke that and say false like this and after that we also need the workspace details right so we're going to say const uh workpace details and set workspace details like this um let me see if we can actually pass these workspace deta details and actually we can't guys yeah so just say this like this and say use State just like this okay we need a timer ref so we're going to say title timer ref and what is this I'm going to let you make a guess but if you can't it's basically a ref to keep track of a um of a timer right like a set timeout that we can use to debounce this um title change so when the user actively changes the title we're going to make API request but only after the timer expires okay so say use ref here and we're going to set this return type to something else so we're going to say return type like this is going to be type of um set timeout okay like this and then after this we want to say const uh these are some states to basically uh keep some loading States for application which is when we upload an image like the logo or the profile pick or um you know some sort of um something else we need to have some sort of load loading States right so we're going to say uploading profile pick and then set going to copy this paste it here and say uploading profile pick equal to use State and this is going to be set to false and after this finally I'm going to say work in progress um portal so payment portal okay because a user can also change their payment portal um their billing options right from this settings page okay so then uh what we want to do is we want to create a bunch of functions here so the first one is we want to be able to add collaborators right we want to be able to remove collabor we also want to be able to save our changes um for the input field so we're going to say um like onchange workspace title like this I guess all on changes right here okay and then we need to have some onclick alerts so on clicks right here okay we need to have clicks for a bunch of them so um we're going to have that right there and then we might need some uh some other helpers from the effects such as fetching details so we can show the Avatar right fetching um um Avatar details from our superbase storage and then we also need to get the workspace details from here well we also might need to get all the collaborators so we can say get um all the collaborators from here and then we'll need to do we'll also need to create a uh portal here for stripe and stuff so we're just going to say work in progress uh payment um portal right okay payment portal redirect like this okay and after this I think this is pretty much it yeah so let's go ahead and get started so the first thing we're going to do is we're just going to restart our server so let me go ahead and say npm runev and refresh this and um let's give that one second all right guys so in here we're going to open this settings and we're going to do some stuff in here okay so let's remove this settings form let's give this a class name and this is going to be set to flex gap of four Flex D column and in here go ahead and create a paragraph tag this is going to have Flex item Center Gap 2 and margin top of six inside this we want to have a briefcase logo which comes from Lucid react and give it a size of 20 so this is kind of like the uh the top section it's kind of like uh you can say headers so we have briefcase here and we're just going to say workspace and then we're going to use the separate operator and after this we want to create a div class name of flex flex-all and GAP set to two and inside this we're going to create a label HTML 4 is going to be set to the workspace name and this is going to be name like this and after this let's also I think we need to yeah let's give it some styling so we'll say class name is equal to text- smm text- muted D foreground after this label go ahead and say input name is equal to workspace name like this and then you want to say value is equal to the workspace details so if this exists it's going to be the workspace details. tile or it's going to be an empty string so we're going to set a type for the workspace details so the workspace details here is going to be uh a type of workspace placeholder equal to workspace name onchange workspace name change let's copy this go up top and let's go to our on changes in here we're going to remove this and we're basically going to say const equal to this function here so this is simply going to update the workspace name that's literally it e which is basically of type react. changeevent this is of HTML input so we're going to pass in the input elements event right here and in here we're going to check if there is no workspace ID or there is no e. target. value going to return if there's nothing in there we're going to dispatch an action here called type with update workspace okay and the payload here guys is going to be the following so it's an object here with um let's see what we have in here so this is just going to be everything in the workspace itself so everything is optional so we're just going to say title is going to be e. target. value okay so something is wrong here let's go into our workspace because we how can you even update this without that right State provider like this and we're going to look for update workspace like this and uh we're saying payload action. payLo load. okay that's what it's called I don't want it to reset that ID here okay let's make a quick change guys so let's go into our update workspace which is only being it's only been done inside the settings form have I not used it anywhere else I don't think I have Okay so let's go into the state provider right in here and this update workspace is going to take this and the payload right here is going to be the workspace like this which is going to be this and we need to pass in the workspace ID which is going to be a string like this and of course we need to change this action here to so payload do workspace ID just like this so this is going to be the workspace which is going to be an object with the title set to e. target. value like this and after this we need to pass in the workspace ID if the timer title timer ref right in here okay if this do current if this exists we're going to say clear timeout and we're going to pass in the title Uh ref. current so we can clear the timer the title ref is going to be urrent is going to be equal equal to a new timeout so set timeout and this is going to take an arrow function and we're going to pass in 500 milliseconds and in this we're going to say async await update workspace workspace with the title we're going to create this in a second guys this is equal to e. target. value and we also need the workspace um ID copy this go into your queries which is inside the superbase queries and um let's go ahead and do it right here so let's go up to where we see something called update export const update workspace equal to an async function if so we need the workspace itself so the workspace is going to be partial of workspace and the workspace ID just like this okay so partial like this and the workspace ID which is a string there is no workspace ID we're just going to return like this try catch await db. update invoke it and say workspaces do set the workspace like this do where equal workspaces doid is equal to the workspace ID that was provided in here and then we're going to return data null and error set to null copy this here and return turn it if there is an error here and just say console.log error change this to error um I want to show you guys another way of updating so in a server action you can also revalidate the path okay that is something that we haven't done we are basically using client side so I just want to show you some different ways of doing it so you can say revalidate so re validate path invoke it and you need to pass in something in here okay so you're going to pass in dashboard like make this SL dollar sign workspace ID so it's just going to revalidate that path and fetch new information if needed so we need to put this above this and can return this right here go back here and import updated workspace and after this input guys we want to create another label here so we're going to say label like this and we're going to call this the workspace logo HTML 4 we're going to say workspace logo and we're going to give it a class name which is text SM text muted uh foreground and inside this we're going to say workspace logo and after this create an input name equal workspace logo type equal file accept equal image slashstar placeholder is equal to workpace logo on change here that's going to be onchange workspace logo and then we're going to have a disable which is equal to uploading logo so let's go ahead and create I thought I already did that okay we only had profile pick here so const uploading logo okay this is going to be equal to use State like this and this is going to be equal to false so let's go back down here to this error and this is going to be uploading logo just like this again guys we also have to make sure the user subscription is active before we can use this component so we have to do that in here too so I'm just going to set another work in progress to uh do the subscription right in here so say const onchange workspace logo is equal to Something in here this async function and this is going to be e. react sorry e is going to be react. change event and we're going to say input uh HTML input sorry HTML input element and then inside this we're going to say if there's no workspace ID then we want to Simply return everything and then we're going to say const file equal e. Target do um files like this and then we're going to say dot at zero okay and then if there's no file we're just going to return and then we're going to create a uyu ID so uu ID equal V4 import it and invoke it set uploading logo to true cuz we're going to do that right now and then const data and error is equal to await superbase do storage. from invoke it and say workspace logos. upload let's go back to what we had in our main um settings right sorry when we had a dashboard setup we had some stuff in there so let me go ahead and just copy this so we don't make any error in here and let's paste that in here so we're going to pass in uyu ID like this and um then we're just going to go ahead and you know send this okay and we're going to say upsert to true even though it's not going to be able to do it because this uu ID is going to be uh different every single time and I actually do have a reason why it's better to just create a new line so superbase themselves are actually saying that if you update something even though you have this cache control and upser set to true and all this stuff basically if an image is uploaded it takes some time to uh update everything in the database in in the storage bucket so they they are telling you to just create a new line and then uh you know delete the image or something like that so so what I would suggest is you guys can do that if you want to and to do that you just have to say do remove and then remove the image first and then you can go ahead and upload this new image right here and then after this we're going to say if there is no error then we're going to say dispatch type update the workspace to be payload workspace is equal to logo to data. paath and then the workspace ID right in here and then we're going to update the workspace again to logo to have this path and then we're going to send in the workspace ID and then we're going to set the uploading logo to false so I'm just going to put another comment here and say work in progress uh subscriptions right here and I'm going to just comment this out so after this div create a react fragment and say a label and this label is going to have an HTML 4 equal to permissions and you're going to say permissions just like this and after this just go ahead and have a select component okay which comes from UI um the UI select and basically guys I'm just going to copy what we had in the other place it's literally the same thing there's nothing different okay so go ahead and just copy this entire section guys go back to our um to our components remove the select from here and just paste it okay we're going to have some errors but we'll fix that in a second awesome so we just went ahead and copy pasted that so let's solve this this first problem right here which is this add collaborator okay so this is going to be a function again which is going to do which is just going to set our collaborators guys so let's go up top and have an I mean this is basically the same as the other one you can just copy it okay so I'm just going to go ahead and copy it from that file and paste it right in here and it's the same thing basically we're going to check that there's no workspace ID going to return and this is work in progress we'll come to this in a second basically we're going to check for um their subscription status if it's active they can only have um you know less than two collaborators okay and then we're going to await add a collaborators so we're going to send this this is basically our uh query which we had there too just go ahead and import that and then we're going to set our local collaborators to the collaborator and and then we're going to just do router. refresh for our remove collaborator we're going to create a function here we're going to say REM remove remove coll collaborator equal to this function right here and this is going to be async user of type user we're going to check if there's no workspace ID and if there's no workspace ID we're just going to return and then we're going to check the length of the collaborators if it's equal to one then we're going to set the permissions to price we're going to remove the collaborator but that's done a little later okay it's not done right away and then we're going to do the following which is we're just going to create another uh API um right here the an action a server action we're going to do that in just a second but we're going to set our collaborators to collaborators do filter the collaborator where the ID is equal to the user. ID just like this so let's go ahead and create this action so go to your queries right in here export const remove collaborator equal to an async function which is going to have users like this and we can set it to user array because we can we might want to remove multiple as well so that's why we can just do this also I know there's another way in drizzle guys where you can just remove for many but I'm just going to do this right now okay it just makes more sense to do it this way so we're going to take the workspace ID which is a string okay and uh same thing guys we're just going to copy this from here and I'm just going to paste it in here and the response response is going to be equal to users for each of these4 each async user so first we need to check if the user is in there so we're going to do uh db. query. collaborators doind first where the user right we're going to do this it's a callback function and we're going to say where the user ID is equal to the user ID we passed in and um the workspace ID is equal to the workspace ID we passed in okay if the user exists only then are we going to do the following await db. delete and then we're going to say collaborators do where invoke this and we're going to pass in an and in here we're going to say equal to collaborators do workspace ID and inside this we also need another one which is the workspace ID we just received workspace ID like this and another equal to guys right here where the collaborators do ID sorry user ID is equal to the user. ID let's come in here and this is actually incorrect actually this is fine um this is wrong actually so yeah right here before we do this we want to say remove collaborators import that and this has to be all our um our users right here right so we're just going to set um set it to an array of the users for now and the workspace ID just like this awesome so after this we need to use the alert so we're almost done guys we basically just have to show the alert uh for this for the workspace so we're going to say alert variant is equal to destructive inside this we want to have the alert description like this and you want to set this you know deleting your workspace is going to delete this or something let's create a button in here and we're going to set the type to submit we're going to set the size to SM and then we're going to set the variant to be destructive and then we have a bunch of class names margin top text- smm BG destructive 40 border 2 border Das destructive after this we want to also have an onclick and this is going to be async we're going to check if the workpace ID exist we're going to delete a workspace and we're going to create this in a second I'm going to pass in the workspace ID just like this okay turn a toast like this and this toast is going to have title successfully deleted your workspace and this is pretty much enough and then we can just say router. replace back to SL dashboard because they deleted the workspace so now we want to send them to the dashboard page and that will reroute them to their first workspace or it's going to allow them to create a new one so let's copy this delete workspace and let's go ahead and just build this out out really quick and we're just going to say const delete workspace is equal to a function that checks if we have a workspace ID if not it's just going to return and then we're going to do db. delete workspaces where the equal to stuff in here where it's workspaces doid and is equal to the workspace ID we passed in and in here go ahead and just say delete workspace inside this button and let's just see what this looks like click on the settings and there you go so you can delete the workspace from here now if I delete the workspace I might actually lose all my data so I'm not going to do that let's maybe try it on something else right why not so the private workspace right here we're going to go ahead and say settings delete workspace like this successfully deleted and we're routed back and it sent us back to the workspace okay so it looks like it did not refresh this and but then we have to do some sort of logic to check if we have our workspace okay so let me see what to do here guys just give me one second all right so what we can do here is we can delete this workspace from here okay and we can dispatch that action dispatch like this and we want to say type is going to be delete workspace and we have to provide a payload which is going to be I think an object actually No Object it just has to say um workspace ID like this okay so we want to make sure there's no there is a workspace ID so what we can do here is we can remove this and we can say if no workspace ID return so don't do anything this should solve our problem so if we come in here and click on maybe we can create another workspace in here let's just say test private and we're just going to create it successfully created and you can see the workspace is in here test private workspace and if I click on this and hit settings and hit delete workspace okay awesome there we go we go it's gone so let's go ahead and fetch our workspace details I actually wish I could give it to you as a challenge but I I don't want you guys to get stuck okay so I'm just going to say use effect and guys by the way for some reason if I give you challenges and you can't finish it all the answers are going to be in the Discord okay everyone is going to help each other out and I'm also going to be there so I will literally help you out okay I want you guys to genuinely take part and take action rather than just watching videos every single time okay start building and thinking okay so let's go ahead and say const showing workspace equal to state. workspace doind like this the workspace from here where the workspace do ID is equal to the workspace ID if this is true here also we can pass in the workspace ID like this and the state because we need both of these the dependencies right here if there is a showing workspace then we're going to set the workspace details to that showing workspace just like this and now we have both our local States and the states that come from there so if I click this there you go you have the test workspace the name right in here so let's go ahead and test this workspace name so if I change this you will U okay actually we can't change this something is wrong here all right guys so the issue why this was not allowing you to change anything is because we said action. payload but in reality the payload has a workspace and the work space ID I think we recently just made this change so just change it to this okay now if you click this and change it there you go it changes and it looks absolutely amazing all right so I wanted to touch on one of these issues which is in here if I make a change it does not actually update the state in here why is this the problem well if you look into our components we are using the server side default data to kind of not this default data but we're just using these workspaces from the server directly from the server component directly and that's why we're not syncing it with the local States so we already did this before for our folders so we're going to do something very uh similar guys okay so let's go ahead and do this right here and we want to say State and also the default value okay we need both in here and it's very simple we're just going to say const find uh maybe selected workspace equal to state workspaces doind um like this and we're going to get the worksspace and we're going to say where're workspace doid equal to the default value just like this okay and um sorry default value. ID guys and then here we're going to say if you can find a workspace like this if find the selected workspace we're going to set the selected option to this uh find selected workspace so we're just syncing it up like this okay okay now if you go to settings let's hope this works and you change it there you go guys in real time it changes everywhere across the entire application if you did this on your own good job to you all right guys now we're going to build a component for the editor and this editor is going to be reused for our workspaces our folders and for the files as well okay right now we're just rendering an empty you know just returning text but now we're going to create that component and we're going to make this happen with this package called quill and the reason why I picked quill is because they use something called deltas and Deltas are basically um think about it this way guys so if two people are editing a document but both of them make a change at a single location um one of them is going to win right and you cannot just take one person's text or data and append it to the back of the other person's data you cannot do that so what Delta's help uh accomplish is basically it shares the positions the op operations which is insert and also at which location with the attributes and all that kind of stuff so all the complexity is already done for you so this is why we uh we picked quill for this application so go ahead and um close your terminal close your server like this and just say npmi quill okay so install this and this is actually not a re this is not react quill this is um it's just vanilla JavaScript we have to make it um Quil like react friendly okay so we're going to do that so the first thing you want to do is you want to shrink all of this go into Source components and we're going to create a folder here called quill Das editor like this and inside that create another quill dedor dtsx like this okay inside here we're going to have all the logic for uh the component and we're going to reuse this component in all of our files okay so before we do this let's just do rafc and we're just going to return Quil editor like this okay now you want to go into your app folder right here Main and then go into workspace and then in the page. TSX right now we're just returning this right we're just returning this right here we want to actually use this new coil editor that we created so first of all let's understand what's going to happen in these pages so in these Pages we need to fetch the details for um the ID that we're on okay so if we're on a workspace we need to get the workspace details if we're on a folder we need to get get the folder details and in the file you know the file details so that's what's going to happen in here and then we're going to take that data and pass it into our quill editor and the Quil editor is going to do whatever it has to do okay so that's what we're going to do here so um right here we have access to the params because this is a page right is a page. TSX file so we get um we get access to these params right here so first we're going to get the workspace details here and then we're going to go ahead and uh render out our component so first let's just um imagine this exists here which is equal to await like this get workspace details and I've already gone ahead and created this and I want this to be a challenge for you okay so go ahead pause this video and try to build out this query this action inside your superbase um query folder so if you go into Libs superbase queries go ahead and build that function um that action in there so pause the video do that and then come back to this video all right guys hopefully you got it right if not don't worry I'm going to show you exactly how to do it um so in here basically we're going to create this action and it's called get workspace details okay so it's an async function that takes in the workspace ID and first we're just going to check if this workspace ID is valid okay so let's go ahead and do that here and then if it's not valid we're going to just return an object with data like this with data set to an empty array so that nothing breaks and um we're going to just send error like this okay if not we're going to do await db. select. from workspaces where the workspace ID is equal to the workspace ID we want okay and we're going to limit that to one and you can also use dbquery here guys uh query dot um you know the table name and then you can do find one or you can do that as well okay but uh for now we're just going to use this and then if the data exist right we're just going to return this all right so return this if if not we're just going to return the same thing that we returned here okay straightforward right nothing crazy and then we're going to check if there is an error like this or if there's no data. length because we're returning an array and then if so if this is actually um the case we're going to redirect the user to our dashboard page because our dashboard is going to do all the logic in here okay so that's why we're going to do that and then here what we're going to do is we're going to return a div just like this give it a class name of relative and in here we're going to render our quill editor okay so let's import our quill editor from the new folder that we just created just like that and we can just import it like that okay now our quill editor is going to take a couple props and the first one is called dirt type because we're using the same component for everything so we're going to call this workspace and then it needs the file ID and let me explain what this file ID is guys so basically this file ID is not the this file ID this file ID basically represents the ID that we're on so you see that file ID right so our workspace has a file ID or basically an ID the folder has an ID and the file has an ID so that's what this file ID is we're going to use this ID to basically you know fetch details and do all that kind of stuff all right also to create rooms and things like that we're going to set this to ps. workpace ID because that's the ID we're using correct and then here we want to say d details so this is the directory details is going to be data at zero or we're just going to return uh like an empty object right here awesome create this interface all right so we're going to say interface like this Quil editor props is an object with the dur details set to a file okay which comes from our super based types or it's going to be um a folder again from superbase types or it's going to be the workspace okay just like that and then here we're going to say file ID is going to be a string and finally we have the dur type which can be of only three types which is the workspace or it can be of type folder or it can be of type file okay awesome and now let's go ahead and use this here so we're going to say react. functional component and you want to paste this in here and go ahead and extract these values like this okay just like that awesome cool now that we've extracted those values um we're going to there's a lot that's going to go on in this component okay I'm going to try my best to keep it at the uh to bring perfect timing so that it all makes sense but what we're going to do in here is basically render out our quill editor right and uh we're also going to use socket.io to create real time uh connections and Communications between different clients okay and I'm also going to show you new features in super base like presents and um some other real-time features in in there too so you guys know how to work with different type of Technologies okay so first thing we need here is two variables so we need to basically Mount our quill editor here okay so what we're going to do is we're simply going to say const quill so let's just create a variable to store that in here and we're going to say set quill just like this and this is equal to Ed State and you guys know what to do when you're using use State go up top in here and you want to say use state in here okay and um the reason why we're doing this is simply because um you know we have a lot of states to manage real-time data we have to store a bunch of components we could make it a server component no problem but I want to explain a a problem that comes with u using this um you know nextjs for this so there's something called as router cache guys and what router cache is basically on the server there's a cache but also on the client side there is a cache okay and going in here and setting the component which we're going to do anyway which is in here if you go to the page. TSX if you go up here and set this to um you know Force Dynamic it's actually not going to fix our problem and the reason is because um what's what's going to happen is this is only for the server side data to send new data but on the client side we're actually caching everything and I did some research and nexj 13 says that it's actually it not possible to opt out of this router cache there's a 30second um opt out period and only after 30 seconds can we opt out of that so that's the reason why we want to actually use a client component in there so that we can fetch new data every single time okay I hope that makes sense all right so this Quil quill editor I'm just going to give it of type any right here and just set it to null okay and um we're going to use this to store that quill editor and we're going to need a couple other things from our use app state so let's go up top and say const State workspace ID folder ID like this and we also need dispatch which comes from use App State okay let's go ahead and invoke that like that awesome and now let's first basically create that mounting to mount our Quil editor all right so let's go here and let's create that area where we can mount the component okay so the first thing we want to do is we want to create a react fragment inside this right here and then let's create another div this this div is going to have an ID set to container like this and inside this div guys inside this is where we're going to put our quill editor okay so to access this element we can use a ref okay and we're going to create this ref in just a second it's called wrapper ref just like this and we're going to go up here and we're going to create that okay but before that let's just give it a class name to and this is Max width is set to 800 pixels just like this okay so this way our our editor will be right in the center so we're going to have some errors here and that's because we don't have a client component what is this oh this is actually called use client not use State all right awesome so let's go ahead and build this wrapper ref okay so come up here and you want to say wrapper ref and this is going to be a used call back hook right here okay so we're going to set this to something like this for now and then create an empty dependency array okay okay all right guys so for this to work for um our wrapper ref to work quill actually needs the window object okay it needs to be present and um for that case we need to make a quick like check okay so we're going to say type of like this window is not equal to undefined all right only if it's not equal to undefined then we're going to check something so we're going to check for wrapper and this wrapper actually comes in from here okay we're going to check if if there uh if the wrapper is equal to null and if it's equal to null we're just going to return out of this okay we need the wrapper to exist so that way we have access to that um to that element where we can place it another thing here guys is if we just run it like this and append it right append our quill Editor to the uh to the Dom every time you save it's actually going to uh append a new one so we don't want that we have to actually clear what's in there so let's just say inner HTML equal to an empty string so we're going to clear this and then we're going to create our editor here so we're going to say editor equal to document.createelement like this and we're going to put a div right in here and then we're going to say wrapper. append right append invoke it and pass in the editor just like this okay awesome and after this now we can go ahead and create quill so we're going to say quill equal and we need to dynamically import this so we're going to say quill equal um await import like this and we're going to import quill like this and we're going to say uh default okay and since this is a um async function let's make sure to mention async up top and after this is done here we're also going to set up cursors but we're not going to do that right now so I'm going to put a work in progress flag and I'm going to put in uh cursors like this okay and you'll see um you'll see in a bit what that looks like but right after this let's go ahead and register um um actually we don't have to register anything in here cuz we already created this component right so let's go ahead and say const Q equal new quill invoke it and pass in our editor right and it also takes some options so we're going to provide our our theme and our theme is actually called snow and we have modules and what is this modules so in this modules guys you can basically create custom components custom modules like cursors images and you can create any component you can think of and that's where we will be creating our cursors to okay so we're actually going to provide a toolbar cuz this module has uh toolbars that you need to provide and it's basically this object guys so I'm just going to copy this and paste it it's nothing crazy it's just an object with all the stuff that we want we need bold italic underline all these kind of things okay we need these options so we're going to go in here and say toolbar options just like this so now it's kind of uh now it's wired in basically okay and right here if we were creating our cursors we would actually put that in here so I'm going to say work in progress cursors okay we'll get back to this in just a second so once this is done then we're going to set quill to be Q so now we have set quill to be q and now since we passed in this theme guys right here we also need to import our theme so you want to go to the top right here and you want to say import like this from quill SL SL dist slill um. snow. CSS not scss sorry okay with is set yep 800 pixels now it should be set okay awesome so now you see that this is not centered since we imported this this looks great right here okay it looks awesome and the max with 800 pixels now it should be set okay awesome so now you see that this is not centered so we need to do a couple things which is so go ahead and create a div like this and encapsulate all the stuff in here there you go you see it actually did that because we moved right so that's the reason why did that okay and now we want to provide some class names here so we're going to say class name Flex justify center items Center Flex call margin top of two and relative all right there we go so we also gave it some spacing up top awesome and now guys you're going to realize that your editor looks different from mine and the reason is because I have gone and spend some time to actually make it look a little prettier okay and I have everything already set for you so all you need to do is go into Cypress um into the GitHub repository you want to go into Source go into app and then you're going to find global. CSS in here okay so go to the bottom where it says layers right here and copy everything from here guys just copy it and paste it it's just like it's just a sugarcoat or application it's nothing crazy okay so I don't want to waste time doing that c CSS stuff so basically what we're doing is we're targeting the CSS classes that quill uses and we're just kind of resetting it that's literally it okay so hopefully you can have a something similar to this and now when you hover over it you see we have a blue color showing up and also that that ugly box has gone and it looks much better okay awesome all right so the next process is we need to get access to these details right the directory details and we also need to sync it up with both the server side data that we're getting and also the client side data okay and I I just explained the reason why we need to do that so uh what we're going to do and if you forgot for some reason it's because of the router cache we need to kind of refresh it okay so you want to go up here and we're going to say const details equal to um use memo so first Let's do let's say use memo like this and you want to pass in a callback function oops um sorry guys yep you want to pass in a callback function like this and in here we're going to basically do that logic so let's just create a variable here called selected directory and we're just going to look into the state right here our local app State we're going to find those um the directory details and we're going to render that if it exists and if it doesn't exist we're going to render whatever we get from the server which is these directory details okay so let's go ahead and check if the directory type is equal to file in here if so we're going to do something if not we have to do something else so I'm going to go in here and say folder and here I want to say workspace just like this okay and actually you could put this in a different file if you want to because I've seen I've seen a pattern of using this on and on so you can just create a helper function uh inside your Libs folder like this and create a utility folder and maybe you can put some stuff in there okay I'm going to leave that up to you to improve and optimize the application but um this is what we're going to do right now we're just going to say selected directory is equal to state. workspaces doind so we're going to search for that file right so we're going to get the workspace and we want to check whether workspace doid is equal to the workspace ID that we're on right now okay and once we get that then we need to get the folders because these are files right we need to get the folder that we're on and we need to find where um the folder. ID is equal to the folder ID that we're on as well okay and finally we want to get the files like this and if that exists we're going to say find like this invoke it and then we want to get access to this file and then say where file. ID is equal to the file ID and this file ID comes in from our props okay that's how we can get access to that to those directory details and finally we're going to do uh selected directory equal to state. workspaces do find guys I hope you are doing this with me because that's the best way for you to learn okay so go ahead take your computer if you haven't already just watch this whole video again and do it with me that's the best way for you to learn okay so we're going to say um workspace and we want to find where the workspace ID is equal to the workspace ID that we're on and if so we're going to get the folders find like this find where the folder like this is the folder. ID is equal to the file ID that we're on okay is equal to file ID just like this so now we're going to get access to uh that directory okay and then finally for the workspace we're just going to say selected directory equal to state. workspaces doind uh where the workspace ID so workspace do ID equal to the um file ID again awesome guys and now we need to check so if anything is in the selected directory we're going we're going to return our selected directory if not we're we have to return a new object okay and the reason is because some properties are not available for um the folders and the files so uh for the workspace for example so uh we're going to return um the following so we're going to say title is going to be directory details. tile and then here also guys we need to pass in some dependency so we we'll just pass in the State uh we'll pass in the workspace ID and I think we also need the folder ID right yep awesome and in here we're going to pass in this we're going to say icon ID is going to be directory details . icon ID and then we need the created at is going to be directory details. created at and then we need data which is directory details. dat and then we need intr okay this is also going to help us get you know show the error on the screen if the file was deleted so we're going to say intr is going to be directory details.in TR like this awesome and then finally we also need the banner URL directory details. Banner URL that should work awesome and let's just return this as workspace um or a folder or a file so we don't have any errors here awesome also I just wanted to point out if you wonder why there's 4 400% of the folders are completed but uh we only have three two folders right the reason is because um we have actually gone ahead and pushed some to trash so that's why you can't see it here and um that's why it's showing this 400% okay so um so now that we have this details we have what we're on so the page that we are on that's what we have so let's go down here so the first thing we're going to do is the in TR stuff so we're going to show up top if the if this workspace or the folder is in the trash okay so let's go in here um for the workspace it doesn't really matter but we're just going to put it in here so that it can be used for the files and folders okay so create a div and say relative like this and in here we're going to see we're going to say details. intr so if this element if this um directory is in the trash then we need to return something so I'm just going to say um article like this and this article is going to have the following class names okay so we're going to say padding y of two BG of this hex code which is EB 5757 Flex from medium devices we want it to be Flex row flexx column justify Center item Center Gap 4 and flex uh Flex wrap okay and then the next one is basically going to be a div in here so let's go ahead and create a div and give it the following class names okay so this one is flex Flex column from from medium devices Flex row Gap 2 justify Center and items Center okay then let's go ahead and create a span inside this and we're going to give it the following class name which is text White like this and we're going to say this um directory type okay we know folder file or workspace from here right so this is in the trash okay okay and let's create a button right here okay UI button just like this and inside this button we're going to do a couple things so let's first set the size equal to small we want the variant to be equal to um outline like this and then we're going to give it some custom class names okay this is going to have background transparent we need border border white text white hover BG wh hover text actually let's set it to this one and let's put that in there so that should work and inside this button you want to say restore so this is the restore button so that you can bring it out of the trash okay and we of course have to P pass in a click Handler so let's say on click equals to uh we'll say restore file Handler okay we'll go ahead and create this in just a second but let's go ahead and build the other button too which is basically the same thing so let's go ahead and copy the same stuff from here paste it in here right just like this so in here we're basically going to say um instead of restore it's going to be delete okay so this is going to permanently delete it so you can change this to permanently delete if you want so I'm going to say delete file okay so let's go ahead and build out these functions they're actually pretty pretty simple nothing crazy here um it's just a simple API request okay so let's go ahead and uncomment these restore file Handler so let's just scroll to the top after all this stuff okay and we're going to say const uh restore file Handler is going to be an async function and um we're going to do this so we're going to say if the directory type is equal to type of file okay then we're going to make sure we have the folder ID so we're going to say folder ID exist if not we want to return okay and then we're going to dispatch a new action and this uh actually it's the same action and this one is basically called update file okay we're going to update a specific file and what it needs is a payload which is set to an object and let's go ahead and import all these values just like this okay so the file is basically going to be an object within trash set to an empty string because we're bringing it back out of the trash okay and the file ID um this file ID I think it can yep it can be this workspace ID um what's wrong here okay so we need the workspace ID too so we'll just check and make sure the workspace ID exists if it doesn't exist get out of here again okay so folder ID is going to be the folder ID and workspace ID awesome awesome guys and now we want to say await update file like this and you want to invoke it so first um is the file itself so this is going to say in TR set to an empty string and it also needs the file ID right yep so we can say file ID just like this awesome guys great job and now we want to check if it's a folder so directory uh type equal to folder like this if there's no file ID actually if there's no folder ID like this so we can just say if there's no workspace ID we want to return okay and then we're going to dispatch an action with type like this set to update folder and we need to pass in the the pay load like this which is inside this so payload is going to be an object set to the folder we need folder ID and workspace ID so the folder is going to be in trash set to a string and the folder folder ID here is going to be the file ID guys all right and the workspace ID we can just pass it in here okay we need to make sure our file ID exists so let's just say if there's no file ID okay just for this typescript error I think that should actually solve this problem um let me see something seems to be wrong here so this is actually folder ID set to the file ID all right there we go guys so I don't think we actually have to check this and the reason is because our file ID is set to a string okay cool and then we'll just say update folder like this and this has to have in trash set to an empty string and the final thing is the file ID just like this awesome uh guys great job so now this should actually work but um we cannot test it on the workspace actually want all this data here so we will test it in the on the folder in just a second okay so let's go back up here here and let's just see what this element looks like so okay we have the delete file 2 so let's go ahead and set the delete file where is that right in here okay so we'll say const delete file Handler is equal to this right here and this is going to be an async function and what we're going to do in here is we're going to basically copy all of this and we're going to check directory same thing but this is going to be delete file like this and um our payload we're going to get to that in a second and this one is going to be delete folder okay these don't exist obviously so I want you to take this up as a challenge I hope you know what you're supposed to do now but if not no problem I'm going to show to you in a second go ahead pause this video create these two actions and then come back to this video all right so let's go in here and where we are saying add file we're going to create another object give this a t type and we're going to say delete file just like this okay and this is going to need a payload and what we need for this is basically the workspace ID which is going to be a string we need of course we need a folder ID right which is going to be a string and um we also need the file that we want to delete so file ID which is going to be a string as well okay and now that we have this let's also go ahead and build it out for the folder so hopefully you got this one right to if not no problem this is what you want to say delete folder like this and the next property is going to be the payload payload is going to be an object payload needs to have the workspace ID so workpace ID let me shrink this so you guys can see clearly and this is going to be a string and then we also need the folder that we want to delete awesome hopefully you got this right okay if not no problem don't worry about it so let's let's go ahead and delete the file so right after this we're going to say uh case we're going to set this to delete file we're going to return something in here so for delete file guys basically we're going to return everything that's in state but we're going to set the workspace we're basically creating a new state okay that's basically what's happening here so state. workspaces do map we're going to get the workspace actually let's do this we want to first see if the workspace doid if the workspace from here so we want to save this workspaces if the if the workspace ID is equal to action. payload do workspace ID then we're going to do something um if not we'll just return the old workspace the other workspace okay so in here we're going to return a new object with everything inside the workspace but we're going to set the folders to be something else which is going to be workspace do folders. map and now we're going to check in here so we're going to get the folder and we're going to check if the folder. ID is equal to action. payload do folder ID okay if so we'll return that if not we'll just return um something else okay so we'll say return the folder itself if it is we're going to return a new folder okay for that folder but we're going to set the files to be something else cuz we're deleting a file right so the file is going to be folder. files. filter and we're going to filter for the file where the file. ID not equal to CU we're filtering not equal to action. payload file ID awesome hopefully you got this right cuz if you did great job okay it's really good I'm really proud of you where is this yep we have update folder we can do it right here all right now we're going to work on the delete folder okay so what we're going to do in here is we're simply going to return return a new state um State like this so everything in state but we're going to set the workspaces like this to be state. workspaces do map so we're going to uh map over this and get access to the workspace and we're going to say where workspace doid is equal to um the action. payload do workpace ID so let's wrap this in a if block just like this and and in the end we'll just put this curly bracket okay awesome so if this is the case then we'll do something if not we're just going to return um the workspace like this okay so so we're going to say if workspace doid is equal to action. payload do workspace ID like this and then if so uh we're going to do something if not we're just going to return the workspace itself okay so if so we're going to say return a new object with everything inside the workspace but we're going to set its folders to be something else and we're since we're deleting a folder we just have to say uh workspace do folders like this filter for the folder like this um where the folder. ID is not equal to action. payload do folder ID so we're basically returning a new set of folders for this and we're just filtering it out with that okay awesome guys um great and now what we're going to do is we're going to head back into that so let's close this let's come in here and now for delete file we need to pass a payload and this payload is going to throw a bunch of Errors so let's go ahead and do that so this just needs let's see so it needs the file ID which can be the file ID that we need to delete the folder ID and the workspace ID awesome and then we can um we need to create create a new action here so let's change this to delete file okay so this is causing some issues so here's what I'm going to do okay I'm going to go down here and say U delete file Handler just like this okay and now it's not going to cause any more issues so here we're going to change this to delete file and since we don't have this let's go into our schemas I'm sorry let's go into our queries like this and where we have our delete file we can go ahead and delete it get file okay let's just do it in here so export const delete file equal to an async function like this and this async function is going to need the file ID that we need to delete right so we're going to set this to a string like this and inside this we're going to check if there's no file ID of course you can do the validate stuff we're just going to skip over that real quick and we're just going to say if there's no file ID just return and D b. delete files. whereare equal files equal to the file ID we just passed in okay simple and let's also do it for the folder might as well we're already at it so export const delete folder equal async okay and this is going to be the folder ID and set to a string okay and in here we're just going to say if there is um no folder so I'm going to copy this like this okay if there's no folder ID like this we're just going to delete and I think do we already have delete workspace let me see delete delete workspace is already done for us so we're good to go I'm just going to check the fold all right so I think this is good so let's go back in here and let's import that so delete file from the query like this and this only needs the file ID to delete awesome and same thing here so this one is going to change to folder ID so let's check this it needs the folder ID which is supposed to be our file and the worksspace ID and we can come in here and say delete folder just like this awesome and this only needs our file ID which is basically the folder okay awesome great stuff guys so let's see if um yeah we would have to also render this for the other components so let's go back in here go into your files right in here so go into Source app go into Main sorry go into your workspace into folder click on page and you're going to do the same thing in here so go ahead take this up as a challenge and build this entire component for the folder okay and do the same thing for the file if you don't know how to do it it's okay guys pause the video give it a shot and then come back and I'm going to show you exactly how to do it all right guys awesome so this is what you have to do for the folder okay you want to go ahead and say um this Force Dynamic up top you want to import react uh import our quill editor and we created a new query I'm going to show that to you in a second but I want you to take it up as a challenge we already did the get workspace details so it's exactly the same there's literally nothing different other than the name and the string that's being passed in okay so go ahead and take that up as a challenge if you still lost it's all in here okay copy and paste and then we are also getting redirect so we're just going to get the data if there's if there's an error or there's no data we're going to send them to the dashboard page and um if everything looks good we're going to go ahead and render out this component okay all right and now to test guys to make sure that everything is working once you're done creating this component for the folder um just go ahead and click on this okay I clicked on this and it's rendering and if I go to workspace it's rendering awesome great job so now let's move on to the file so creating the same component but but under the file um param under the file folder just like this all right guys hopefully you got it right this is exactly what you need to do it's the same thing there's literally nothing different okay so you want to do this this and also before we jump into it there might be an error uh when you click on the file when if you did test before okay and I'll show you why we made that error and we will fix that in just a second okay so uh we're going to say file like this and we created another get files details with which is exactly the same okay nothing different just change the file ID and you can copy paste it um you can see it on the screen now or you can copy paste it from there okay nothing different in here so we're going to check if there's an error or there's no data if that's true we'll just send them to the dashboard page and in here also make sure you're changing the directory type to file and folder for the other one okay or else it's not going to work so make sure you do that it's super super important so now let me show you the error I actually fixed the error right which is if I click on the file it renders it out um correctly Let me refresh this real quick um let me go back to this click on this if I click on the folder and um if I click on a file it's rendering out everything perfectly okay so I'm having no problems here but you would probably realize some error and the error is actually happening in our dropdown component so let's go into Source the shrink everything Source components sidebar you want to go into dropd down. TSX so in here guys where we're navigating you can click this okay and in here where we're navigating we're basically um setting this right here so before this it was set to accordian ID and if you remember we actually created a custom ID file ID and that ID had this weird text in it and something else in it and that basically allowed us to set default values okay so now if I refresh this page you will see this file is automatically clicked and is loaded accordingly right that's why we needed those values this this custom file ID right here so when you clicked on it before it was pushing that ID to the URL which is invalid so that would throw some uyu ID errors for you that's the error that you were uh you were facing if you did okay if you don't have this error awesome but all you have to do guys is you have to say accordian ID dosit folder and you want to take the first element because the zero element is the folder ID and this one is the file ID okay awesome great job so let's go back to our file I'm just going to close this here and now if you click through everything it's all going to work perfectly fine with no error so you see it's rendering that if I click this it's rendering my my folder and now it's rendering my workspace and I can go back and forth with no u no issues great job guys so now let's move move on to creating um all the other elements inside our editor go ahead and scroll to the bottom here and we want to test this in trash um you know to make sure it's working so if I clicked on the folder and I deleted it there you go it shows up on top and it says success moved folder to trash and if I refresh this page like this you will notice that it is actually going to show in here let's go ahead and restore this file and boom there you go it came back the folder came back along with the file okay and here's a challenge for you we actually didn't incorporate this but I want you to take this up as a challenge right now if I delete a folder the file is not being deleted and of course the file needs to be deleted am I right so all you have to do I'm going to give you the answer but I want you to try okay if you don't know the answer I will be in the Discord and I will give you the answer but you need to try so go go down here and what you need to do is inside the providers in our state provider okay let's just say for the file okay we're basically going and removing and just adding this um the new title the new in TR property with a string okay saying in the trash or something like that right so what you would need to do is create a new action called um add to trash or move to trash action and in that action you need to first move the folder to the trash so go ahead and move the folder to to the trash and then you need to also move all the files that are inside that folder into the trash okay I hope that makes sense um that's the that's the right way to do it okay and when you bring it back when you bring it back it's all going to work it's all just going to pop back in because what you're going to do is you're going to set a restore folder action and that restore folder action is going to first bring the folder back and then search for the files and bring each of those files back I can't wait to see you guys do this this is a great challenge for you to do I will give you the answer but I want you to try there you go it's working perfectly and if I clicked on the file for example let's just try this out so I'm going to hit delete boom there you go this file is in the trash I'm going to go ahead and copy this link so I don't lose it because we we haven't built our trash functionality yet and if I click on the folder it's still going to exist but if I go back to this file there you go and I can restore it done so after this div guys so after you put the delete button create a span and we're going to give this a class name of text small and text white and in here we're going to basically put our details. intr so if I delete this file for example it says deleted by web prodigies it just says my name in there so everyone knows that oh this person deleted it so they they can go and absolutely blast them and now you can restore this file back awesome so after this article right here we have this div hit enter and create another div so you want to say Flex Flex column Flex column reverse SM Flex row because on mobile we want it to be reversed okay and then from the small devices justify between justify Center by default and from small devices item center from small devices padding 2 and padding 8 right in here and what we're building here guys is basically the breadcrumbs for our application so we like to show the user where they are actually located cuz right now I don't know where I'm at right it just shows this file so inside this div we're going to create another div like this and we're going to create a variable up top okay called breadcrumbs so we're going to say const breadcrumbs equal to use memo invoke this and we want to pass this empty dependency and we need the state basically we are going to look into our local state and search for the details that we need and we're going to append it into a string and show it right up top in here first thing we need to to do is we're actually going to use path name guys we're going to import path name up here so let's go up top and we're going to say const path name equal to use path name and invoke it and then if not we're just going to return but we also want to make sure there is State and workspaces set and our we want to make sure we have our workspace ID okay we might also need the folder but let's let's just see right now I don't think we do what we're going to do is create um a bunch of segments here so equal to path name dos split like like this and we're going to split it by the backslash and then we're going to filter for some values okay this is another way to filter we did Boolean before so we're going to say value where the value is not equal to the dashboard okay like this and we also want to make sure the value is true so we're going to say value like this awesome then we need to say workspace details equal to states. workspaces you see we're using this so often guys so it would be great if you put it somewhere else but I'm just going to do this because practice makes perfect and it I really suggest you type it out it's going to make you work so much quicker workspace doid is equal to workspace ID just like this so now we have the workspace in here and then we're going to create the breadcrumb so we're going to say workspace breadcrumb we're going to check if there's anything in workspace details if there is we'll do something if not we'll do something in here so we're going to create a string literal and say dollar sign workspace details. um do ion ID like this and put a space here and then we need the workspace details. title if not we're just going to uh return an empty string so we're going to segments. length equal to 1 that means we know we're on a workspace so we're just going to return the workspace breadcrumbs just like this if not we're going to again find for folder segment equal to segments at one and then we're going to say const folder details equal to workspace details folders. find because it can only be in the same directory so we're going to get the folder where the folder. ID is equal to the folder the folder segments and now that we have this we're going to create our folder breed Chrome and this is equal to it's a same thing guys it's same thing that we did up here but we're going to put a backslash before the icon ID and we're going to check the segments in here too so I'm going to just copy and paste this here and check it if it's equal to two if it's equal to two then I'm going to return a new new type of string which is first the workspace then our folders so go ahead and build this out for the files it's a challenge go ahead and take that up as a challenge and build it up for the files if not pause the video and then if you can you can come back and I'll show you how to do it all right guys hopefully you got it right if not it is actually insanely simple it's the same exact thing okay you're going to check for the file segment create a file just like this and um then you're going to check for the breadcrumbs by just saying if the details exist then you want to you know create a custom string with a back slasher icon and the title and you're going to return a new string with everything combined and in here you'll also need to pass in the path name and you'll also need to pass in the workspace ID if you click on Untitled it'll take some time to load but then you'll see that so if I switch now boom awesome and by the way everything is actually synced you see that so if we say Untitled it's going to update in every single place in the application and it also shows the folder title changed awesome if you click on the file it shows that too and you can change this new file name like this and click out which shows success file name is changed okay so after these breadcrumbs guys we're going to build the collaborators icon so we're going to show a bunch of collaborators here if they're working on the project we're going to go right below the spread chrum and we're going to say div class name equal to flex items Center and GAP four this is going to have another div and this is going to to have class name like this and this class name is going to be Flex items Center justify Center height is going to be 10 and in here we're going to basically Loop over our collaborators but we don't have it built so let's go up top and let's just say const collaborators and set equal to use State just like this you can set this to an array of objects and we need the string uh ID which is going to be a string the email which is going to be a string and finally we need the Avatar URL which is going to be a string as well so now let's go back down all the way to where we were creating that and inside this we want to create a tool tip and this tool tip is going to allow us to hover over the um collaborator and get some information so let's create a tool tip like this from UI tool tip guys don't import it from radic okay and then we need the trigger which is tool tip trigger like this inside the trigger we are going to put the Avatar inside this we need the Avatar image and then this needs to be the Avatar fallback just like this awesome right here we want to go into the Avatar and we're going to give it the following class names so we're going to say negative margin left of three BG background border 2 Flex item Center justify Center border white h8 and with 8 and then rounded full inside this guys we have this Avatar image right we're going to just give this a class name of rounded full as well and inside here so inside this fallback maybe like CP or I don't know something like Cypress or something like this so right here we need to say as child right after this we're going to say tool tip content some username for example so if you hover over it it just shows a username so now let's go ahead and loop over all our collaborators and let's um use this component to show them and we want to return this component and this needs a key prop which will be our collaborator dot now we will see none because we don't have any collaborators on this file um let's just create some mock data so I'm going to go up top here and I'm going to say you can use chat GPT if you'd like I'm just going to copy all strings and I'm just going to put something in here what we're going to do here is we're going to change this email let's just say if it was something like this at gmail.com we're going to go down here and this is actually going to be the collaborator do email. substring going to do 0 2 and then we're going to do two uppercase and this is basically going to extract their name and put it in here instead of just showing something like Cypress or something like that and the source for this Avatar in here this is going to be the collaborator do Avatar URL if that exists uh collaborator do Avatar URL or we can just return an empty string and right here after this we're going to create a badge and this badge is used to display whether the document is saving or has already been saved so let's just go up top and we're going to create this uh this state here so const saving and set saving equal to use State and just pass in false uh for now let's go to the bottom and where did we create that okay so right here so after this div okay go ahead and say saving if saving is true go to your Shad CN UI and let's actually install this component so let's search for Badge go ahead copy this paste it and hit enter and what we're going to do here in the meantime is just say badge like this so if it's true we're going to return this badge if not we're going to return another badge so in this one we're going to give it a variance and we're going to say secondary and the same thing uh for this too and this is going to have the following class name background to be orange 600 and then top is going to be four text to White right of four and we'll say Z of 50 and then in this badge we can say saving like this let's go down here real quick and what is this error we didn't run npm run Dev that's the issue and the same thing for this you want to copy this we're just going to change the color hit enter just paste and save and this color is going to be Emerald 600 like this and top four and now we're just going to say saved in here so there you go saved and if you expand it it's going to be there right on the on the top right hand side so we're going to have a banner for all our workspaces our folders and our files as well after this you you basically have this badge right you have a badge here below that one two three divs after the third div you're going to go ahead and say details. Banner URL if this exists then you're going to do something so right now let's just create a react fragment and we'll get to this in a second okay I'm going to mute it so what we're going to do is we're going to say div class name and we're going to set this to relative the width is going to be full and the height is actually going to be about 200 pixels and in here guys just render an image from next image and we're going to get this in a second so this is going to be fill class name set to width of full from um medium devices height is going to be 48 then we also want the height to be 20 we want object set to cover Also let's give it an ALT tag guys so we'll say alt is equal to Banner image or something like this okay so the source again go into your GitHub repository that I have right here it's also in the description and you want to go to your Source go to Cypress go into the public folder and you want to copy the banner image and the banner image is just this thing right here so go ahead and download that image and go into your public folder and we're just going to paste this in here for now it's just a test okay let's go up top okay right up here we're going to say const super base equal to use I'm sorry create client component client and invoke this like this I'm going to click this so it takes me here so we're going to say super base. storage. from file banners but I just want to make sure so let me go in here to our storage file banners awesome so let's go back to our application file- banners like this and then we're going to get the public URL for it which is from details. Banner URL then we're going to say data dopu UR L just like this for now we're just going to you know comment this out and we're going to put a string here Banner image.png there you go guys so now it has our Banner image and it looks kind of ugly and that's because we said object so it's object cover okay there we go awesome look at that looks wonderful and that only depends on if you have the banner image so let's go in here uncomment this bring it in here copy this image and we're just going to to paste it in here like this and let's remove this Banner image from here okay just like this awesome so only if this exists will it will it show the banner image um okay what's going on here all right guys so here was my stupid mistake what I did was I actually wrapped this image in this when when in reality we have to wrap everything this whole thing in it okay that's why the height of 200 pixels was stuck right there and that's why it was causing that weird issue okay awesome sorry about that guys so what we're going to have in here we're going to have the title the ability to upload a banner the ability to remove it and all that kind of stuff so inside this div you want to create another div and you want to give it the following class names with full so the reason why we see this like this is because of flex column all right perfect that goes back to its original position and yeah so you want to say with full self Center the max width is going to be 800 pixels Flex Flex column padding X of seven and from large devices we want the margin y to be8 and inside this create another div and set the class name equal to text- 80 pixel this is the icon image guys Emoji picker because we want to be able to also update this Emoji picker and we want to create a div here and say class and this is going to have a width of 100 pixels cursor pointer transition colors height 100 pixels Flex items Center justify Center hover BG D muted rounded DXL so again we have maxed out our connection slots this is going to be annoying also guys I did try another method which is what I originally had which was using the separate migrate file this is the command okay we're using bun to run that file and I did create the migration. typescript and I moved the a file outside it but I'm just seeing a really weird error guys I tried really hard and I wasn't sure what the hell was going on but um I just wanted to point out that there is another way that I did it before but it's just not working but hopefully you guys can find the answer and let me know okay so just go ahead and put it inside the Discord Channel where we can all help each other but yeah so I just wanted to mention that so if you wondering why I didn't do that that's the reason why and in here you just want to pass in the details. ion ID so when you click this again you can go ahead and change the icon for your file so we're going to say get value in here and this is going to basically have a function it's going to be called icon onchange like this and let's copy this go up top and you're just going to paste it in here equal to an async function and this function is going to get the icon which is a string and we basically want to check if uh to make sure the file ID exists okay if not we need to return and after this guys you want to say if the directory type is equal to the workspace and then I'm just going to duplicate this and change this to folder and change this to file in here I'm going to await update workspace and we're going to set the icon ID to be equal to the icon that we just got in and this also needs the workspace yeah we can just say file ID like this in here we also have to dispatch an action right so we're going to call it type of update workspace we need to pass in the payload which is going to be an object object which needs the workspace and the workspace ID so this workspace ID is going to be um set to workspace ID file ID and this workspace is going to be an object with icon ID set to Icon just like this we did this for the workspace so let's go in here if we change this to a workspace like this there you go changed everywhere right and if you refresh it it's also updated for everything so let's change this back to home looks great go ahead and do the same thing for the fold fer and the file okay take it up as a challenge pause the video and come back to it and I'll show you how to go from there hopefully you got it right if not I'm going to show you exactly how to do it for the folder we need this workspace ID or it's not going to work okay so we want to check if there's no workspace ID and if not we're going to return and then we're simply going to dispatch the update folder action and set the payload to the following which is folder icon ID set to Icon workspace ID set to workspace ID you can just remove this just return only this and the folder ID is the file ID and then same thing here we're just going to update the folder pass in this new data and the file ID itself and same thing here but for this one we need the workspace ID and the folder ID because we're looking for a file and yeah that's it you just want to dispatch this one pass in the necessary values in here into this payload okay and then await update file pass in the new file and the file ID all right guys so after this Emoji picker so now we're going to basically work on um the banner upload button so that way we can upload a banner or remove the banner so after this div just hit enter and create another div and we're just going to say class set to flex Banner upload let's go ahead and create this component like this and this is going to take in some props I'm just going to pass it in right now so we're going to pass in the details and then we're going to say ID equal to file ID and then the directory type is equal to the directory type and then we also want to pass in some custom class names that we can use in there so this is going to be equal to margin top of two text- smm text- muted D foreground padding of two hover text- card- foreground then we need transition all and finally rounded set to MD so this is going to be details. Banner URL if it exists update Banner or if not uh we're going to set it to add Banner okay I know this doesn't make sense right now but just bear with me I'm going to show you what it looks like all right let's go ahead copy this name go into our components create another folder and we want to call this Banner Das upload and then inside that create a banner dot sorry Das upload Das form. TSX and then we also want to create another one called Banner D upload dtsx okay we'll just also use rafc okay so since we have done this already I'm going to just copy this so you don't waste any time and um it's the same thing guys okay we have built so much so far so you should definitely be able to understand what's happening right now but basically we're just using children we're creating class name String directory type which can only be of these these three of course ID is going to be string and the details are going to be one of these also use react. functional component Banner upload props and let's go ahead and extract go ahead and extract these values from here we're just going to return our custom dialogue component that we created custom dialogue trigger and this is going to pull the children right in here in here we're going to set the header to be equal to upload banner and then the content is what we're going to pass in we're just we're we'll just pass in a react fragment for now cuz we don't have the form created class name and let's also pass in our class names from our parameters so let's go ahead and say Banner upload form copy this and go into your banner upload form RFC and paste that and let's import this from here and let's go to our quill editor and let's also import this from here awesome so you see it's showing that button right here and if I click it it's going to show my form on the screen so let's go back now where is that component the banner upload form and this is going to take a couple props it just needs the details which comes from here the directory type which comes from here and the ID we're just passing it down this is going to have the following interface so interface Banner upload um form props going to have details and these details can be of any of these types the directory type is going to be workspace file and folder and the ID is going to be a string also use this props in here we're going to extract the details the directory type and we also need the ID just like this okay so use client const superbase create client component client because we need to upload it upload the image to that bucket right so that's why we need superbase in here and then we also need our state workspace ID folder ID and then dispatch and this is equal to use app State and now we're going to use use form again we already did this um so we'll go ahead and do this here again so we're going to say use form um from react hook forms we're going to invoke it like this you can go to your files in here this this file right here where we created created some types and you can say export const upload Banner form schema equal to Z doob invoke it like this so we're simply going to say Banner is going to be a z. string invoke it and then we're going to say. describe and we're going to pass in Banner image and let's go ahead and copy this and we need to import it right in here so let's get it from those types like that and I'm going to pass it in here here so let's import z. infer type of and then we need to pass in this right here so let's go in here and now we want to say register we want handle submit and then we want reset and the form State because we need is submitting from here is submitting and we're going to change that to is uploading and then we also need errors from here so this is going to be mode on change and then here we're going to have default values which is going to be set to an object and it needs to have Banner set to an empty string go down here remove this and we're going to return a form with onsubmit set to a function handle submit so invoke this handle submit and pass an on submit Handler like this copy this we're going to say const this is equal to a function this is going to be an async function let's also give this a class name and this is going to have flex flex-all and GAP D2 so let's import our label from UI label let's just say Banner image and let's pass in the following class name text DSM text- muted D foreground and say HTML for Banner image and after this guys you want to use an input which comes from our UI input and this is going to have the ID equal to Banner image and type is going to be file and it's going to only accept images so image slst star we also need the disabled prop set to the is uploading and here we're also going to spread the register and you also you need to invoke it my bad Banner so because that's the name of this element and then you want to provide the text here so because it's required so Banner image is required and very simple guys we're just going to say small here say class name set to text- r- 600 errors. banner. message. TW string and then after this we need the button to submit we're going to basically say disabled is going to be equal to is uploading and we need to set the type to be equal to submit let's also import this button from UI button and this has got to be submit not submit and then in here we want to say not is uploading is basically going to be something or something in here right so we're going to say upload load Banner or this is going to be our loader component that we created so now if you hit add Banner it's just a very simple form that just allows you to create a banner so let's go into this in here this is going to give us the values so we're going to say z. infer to import submit Handler which comes from uh react hook forms and this has to take in z. infer type of then we need to pass in our new schema and now we can go ahead and build out the logic for this part so let's get the file out const file equal to values. Banner um if this exist dot at zero if there's no file there no ID we're going to say return and if not then we're going to use a TR catch say let file path equal to null and then we're going to say const upload Banner equal to a async function and here we're going to say const data and error equal to await super base. storage. from file- banners we're going to upload first uh we need to provide this ID and then we're going to say the file Banner Das dollar sign ID so we have one ID for everything and we can set the upsert to true and then we're going to say file like this let's pass in some properties we're going to say cache control and we're going to set this to five actually upsert to True one thing I just want to point out guys even if we did upload and update this image okay the issue is superbase themselves have said that it does take time to update everything in the database and um because of that we end up getting the cached value okay so here's my suggestion and I want to give this up to you as a challenge it's very simple instead of updating the image you want to delete the image that exist in there and you want to provide a new ID if you remember what V4 is we used V4 so you want to create that ID dynamically and you want to use a new string so that you don't get the cached banner I hope that makes sense if not I'll I'll help you just reach out to me after this we want to check and make sure there's no error here if the error exists throw new error you can use a toast and you can show that okay if not I'm going to set file path equal to data. path after this we're going to do the logic here so if the directory type is equal to file then we're going to do something not if it's equal to folder to a work space just like this so Els if here for the file is if there is no workspace ID or there is no folder ID then we just want to return if not we're going to await upload Banner invoke it and then that's going to go ahead and upload the banner to that don't forget we also have to dispatch an action let's give it a type update file so payload is going to be an object with the file set to Banner URL is going to be file path then we also need a couple things here right we need the file ID which is going to be ID the folder ID and the workspace ID and then we want to say await update file and we want to pass in the banner URL is going to be the file path oh and we also need the ID guys and the same thing for the workspace here's a challenge go ahead and do it same thing for workspace and the folder the exact same thing okay you're just going to pass a different action and and do different if conditions and go ahead pause the video and come back to this if you don't know how to do it I'm going to show you exactly how to do it awesome hopefully you got it right if not no problem this is exactly what you need to do what we're doing for the folder here is we're checking to make sure these two exist and then we're just again invoking that function and we're dispatching this action to save it locally and then we're just updating the folder in the database same thing for the workspace check if there's workspace ID upload the banner dispatch the action and update in the database so now I'm going to hit update to test the error checking awesome and it's saying Banner image is required let's go ahead and add a banner just going to put this and hit upload and I think the state was not uploaded okay I think I know what might have happened so our file banners probably don't have any policies there we go so let's just go ahead and just create that so go in here it's okay we're just learning guys it's fine you can do the policies and all that stuff later it's super repetitive stuff and you can use chat GPT allow all access for now we're just going to do it like this let me see what I have for yeah this is okay let me wait let me check something all right so let me go to this what do we have for workspace logos bucket ID okay this is fine so it says something like this and we have authenticated what about the avatars okay so let's go in here new hit this this select everything uh bucket ID avatars text we can set this to file banners so I'm just going to put this down here set this like this and just remove like that and just say allow all access guys you have to do the policies because if you don't do that everyone can change everyone's banner and everyone can access every workspace and all that kind of stuff all right that that's okay I have every everything in detail in the um in the Discord I'll help you guys set all that up even if you don't know how to but I'll give you a quick overview at the end of the video how to do it let's hit review and just hit save policy so I think we're good to go let's go ahead and refresh this add a banner again upload let it take a minute there we go guys awesome stuff so if I refresh okay it's not loading what the hell just happened did it upload in the database let's take a look okay we have the banner ban URL it says banner and it has an ID in here go look at the file banners okay I have it in here okay we have a bunch of folders of course all of these are deleted that's why they're in here and we also have the okay here you go you see this our state does not have our workspace Banner URL cuz it's first showing the data and then it's not there later so all right guys I think the issue is right here the banner URL has to come in from here right something that we're missing so Banner URL is going to be workspaces do Banner URL like this okay and you need to provide this for um the okay so yeah so just to give you more context it's happening in the private workspaces uh the select because we missed that and for the get collaborating workspaces get shared workspaces just like this and now you're going to see it all right so it's just a very stupid mistake we missed that and that's the reason why we don't see it guys so let's go back to um our components and after this Banner upload we're going to have a remove Banner upload right here okay details. Banner URL if this exists I'm just going to return a button button like this return this and we're just going to say remove Banner like that okay we just need to change the styling I think yep so let's first set the variant to be ghost and then we'll give it some class name Gap D2 hover BG background Flex items Center justify Center margin of two text- small and text- muted D foreground width is going to be 36 pixels or I'm sorry 36 not pixels and then padding of two and then round it is going to be medium this we're actually going to use a span in here let's put it inside this and give this a class name of white space no wrap and and font is going to be normal so yeah we have an add Banner now cuz we don't have a banner but if we go back to the test we have the remove Banner right here so I can literally click on this button and it's going to remove it but of course we haven't set that up right now so let's go ahead and do that all right so inside this we have to pass in an onclick which is going to be equal to delete Banner let's copy this let's go up top and we want to say const equal to ASN function so before this we also need a state to show that we're loading something so we can just say const deleting banner and set deleting Banner equal to use State invoke this and say false and let's go to our Banner all the way at the bottom I want you to take this up as a challenge okay try to write this Logic for how we're going to delete it for a file a folder and a workspace pause the video go give it a shot if you don't know come right back and I'm I'm going to give you the answer and show you exactly how to do it awesome hopefully you got it right if not this is exactly how to do it so first we're going to set the deleting Banner to true then we're going to check the directory type if it's a file or folder or workspace and we're going to do a bunch of stuff the first thing we need to make sure these are available before we send the API request so do that here dispatch an action to update the file locally so we change the file Banner URL to an empty string and then we want to pass in these and then here we want to say superbase . storage. from file banners. remove this Banner but with an ID okay remove actually takes an array so don't forget to pass it an array if you had this as an issue um this is a solution and await update the file with a new Banner URL and a new file same thing for the folder there's literally nothing different okay uh we're going to do the exact same thing and the exact same thing for the workspace as well we're going to check if it's a workspace we're going to dispatch this action reset our Banner URL um change the workspace ID I'm sorry pass in the workspace ID as a fi file ID and then await super base. storage. from file banners. remove this file and then update the workspace with the new Banner ID finally set deleting Banner to false so let's go back down all the way to this button here where we say remove banner and we're going to set the disabled uh prop to deleting Banner so let's go ahead and give this a shot we delete it it's gone if you refresh it it's not going to be there anymore let's go ahead and upload a new Banner there you see the error just kind of prevented us from making that mistake by uploading without it so if we go ahead and hit upload Banner um let's see it upload in Real Time Boom there you go Banner is right there remove boom it's gone it's really fun to do that okay I can do that all night after this span guys so now what we're going to do um after this is we're going to just put like an icon here so I'm going to use the X Circle icon from Lucid react and and I'm going to set it size to 16 let's go ahead and invoke that awesome so it it kind of just looks like this okay and you can of course put this above if you'd like I think that looks better right y that looks much better cool and the next thing guys we also need to show the title of the page cuz now it's just showing you know the page itself so we need to show if it's a title and we also might want to know if it is the folder or file on this page as well so go down to this div after this part after this one you want to create a span like this and give it the following class names okay we're going to say text- muted D foreground text- 3XL font D bold we're going to say height of nine okay and this is going to be the details. tile awesome and now you can refresh that there you go you see it right there looks great and um after the title after this span right here create another span and this one is going to be the directory type so we're going to say class name text- muted D foreground text- smm and inside this you're basically going going to say directory type do to uppercase okay just invoke that and now you can see it just says workspace so it gives us more information so if I go to a folder it's going to tell me you know entitled and I don't have a banner whatever it's going to give me the add Banner option and it's also going to tell me it's a folder and again if I go into the file it's going to do the same exact thing it's going to show me it's a file so I'm going to go back to my workspace homepage and um we're going to start building this so now I think we're pretty much done guys we have all the designs setup we just need to put in some logic now to kind of get everything uh you know up and going so let's move on to that part also guys I want to quickly point out something so if you did get this error then this is going to make sense if not no problem you probably you may not get this error okay but if you did um you would have an error in this quill it won't be able to import it what you need for that is you need to import the types okay so you'll get an error hover over that and it will tell you to import import the types I don't know if you remember we did it for one of the other libraries as well it's the same thing okay so go ahead copy that command and you would need to go in here and do npmi and you have to paste that or whatever it will give it to you okay it will literally give you the whole command to type so just wanted to point that error out if you had it um that's the way to solve it okay all right guys to make real time uh communication between our clients we need to use some sort of socket right because it's very uh inefficient to always access the database you know we we need to have some way to br broadcast changes to all the clients um in our application so to make that happen we are going to use socket.io package okay so go ahead close your terminal like this and say socket um. npmi socket.io just like this and go ahead and hit enter okay so that's going to install that package and we also need npmi socket.io Das client um just like this so go ahead and install these two packages and these are the packages that we're going to use use to make realtime data uh for these text on changes great so our first step is basically to create this socket okay and um we know that we're going to need the socket in this component but in the future we might need this socket in other components as well so when you need to share something you can probably create a provider right that's what we did for the other parts of our application so that's exactly what we're going to do right now so go into your providers and create a socket Das provider TSX like this and you actually you don't need to do RFC and we're going to um just do the following so first set this to a use CLI component because it's a provider first create a type called socket context type and this is going to be equal to an object and we're going to set this to socket which can be any and or null and then we also might need the is connected so I'm going to put that in here this is going to be a Boolean just like this and now let's create our context guys so socket context equal to create context which comes from react not VM okay and we got to pass in our so socket context type right in here like this and let's go ahead and uh extract these in here so socket is going to be and we're just setting default values okay um and then is connected is also going to be false like this so export const use socket equal to a function and this function is going to return use context from react we're going to pass in our socket context awesome so now we can use this anywhere in our application and we get access to those variables State sorry not variables and then let's say export const socket provider and this is the provider that we are going to wrap our components in and pass children down into okay so we're going to say uh children and this is going to be an object children set to react. react node and inside here okay we're just going to say const so socket and set socket is equal to use State like this and set this to null and after this we also need the is connected right is connected set connected like this is equal to use State and we're going to set this to false awesome it's actually very simple nothing crazy here we're just setting these states based on an API uh request okay so right now um since we're using socket.io we cannot use the API folder okay so what your going to do is um you're going to create a path that path is going to come from the Pages directory so let's go into your root folder shrink everything so into your Source go ahead and create a folder here so create a folder and we're going to call this Pages inside that you want to create um your API um which is a folder again not a file so API folder inside that we'll just create socket folder and inside that create a file called io. types script this is the way to set up um socket.io on an xjs application that's using the app router inside this iio file we're basically going to uh create the connection listen to changes and all that kind of stuff first thing we're going to do is export const config is equal to an object and it has to have API like this and this is an object again we have to set the body parser um to fults we also need to create our IO handlers so I'm just going to say const IO Handler equal to an arrow function and this is going to get the request and the response and the types for this is next API request and this one can be um next API response um but we're we are going to need the server iio response okay so we can go ahead and create this um server iio response in just a second so um let's go to our types which I think is inside Libs types right in here and we're going to create it right in here so we're going to say export type API response server IO it's equal to the next API response and we're going to extend this uh and we're going to say socket is going to be socket like this which comes from this one okay socket from net and um we're also going to need a couple things here so I'm just going to import this so first let's rename this too so we want it to be net server and then we'll also sorry not this one the socket right the socket's going to be like this let's rename the server so we're also going to need a couple other Imports I'm just going to go up here and I'm also going to import the server but this one as net server like this okay cuz we're going to need it in here and this is going to extend uh with something else so server is going to be the net server that we just created but we want to expand that as well extend that as well and we're going to say iio is going to be socket IO server so this comes from socket IO so I'm just going to say import um server again but this is going to be as socket IO server from socket iio okay not the client the socket iio and now we can go down here and we can say this is going to be equal to socket IO server if we go back to our file we just need to import that so let's say next API response server IO just like this and what we're going to do in here is if there's no uh response. socket. server. only then we're going to do the following okay so first let's create the path so we're going to say path equal to/ API socket iio and then we need to say cons HTTP server equal to net so this is going to be of type net server uh and this net server actually comes from HTTP so let me find that we actually have to create it so okay it's called server from net server so I'll get server from HTTP like this and I'm going to go up here and I'm going to actually read rename this to net server and now I can use this net server in here and I can set this equal to response. socket. server as any okay and um I also want to just quickly check something guys so let's go back to our types files right here and I want to make sure that this net server is not from HTTP so we have server from net okay this looks good I think this should anyways let's just see let's just see what happens okay okay if it doesn't work then I'll I'll figure it out okay and in here we want to basically say const IO equal to new server IO U which we're going to import so server IO again is going to come from socket IO so we're going to say import uh server as server IO from socket.io like this and come in here and we're going to invoke the server IO uh right down here and we need to pass in the HTTP server and some an object with the path okay so the path in here so slash add trailing slash and this is going to be set to false and after this so after this part you want to say iio Doon so this is where we're putting all our listeners and the connections and things like that okay so this one first one is going to be the connection okay so we need to do this for connection and pass in a call back function and this gives us um the socket in here so we're going to say socket. on again so this is where we're going to listen to a bunch of different things so first one we're going to have is create room and we'll pass in this again and we're going to get the file ID when we send it from our client and what we're going to do is we're going to say s. jooin and we're going to say file ID uh when they create the room and we're just going to join the user in there s.on we're going to say send changes so this is the next one um and when we get this we're going to do the following so for this one guys we're actually going to get the Deltas which means the uh the data and then the file ID and then we can go go ahead and say s.2 the file ID so this um this file ID okay cuz we already created the room for it so s. to file id. Emit and we need to pass in receive changes okay so we're going to receive this one this event on the server but then we're going to send another event back to the client so that they can listen to it and then also get access to the Deltas and the file ID and then finally we need one more so s.on this is send cursor we're we're going to get to this I'm just going to create it right now cuz we're already at it so cursor Das move okay and this comes from Quill's uh selection uh onchange but you don't have to worry about it right now cuz it's not the most important thing so we're just going to put range file ID uh and the cursor ID and same thing here we're going to say s.2 file id. Emit and we're going to emit receive cursor move and we need to pass in the data so that they can access it in there so that is the range the file ID ID and the cursor ID this range guys is basically a part of Deltas okay it's just the updated different format for Deltas so after this right here we're going to say res. socket. server. iio equal to IO like this and at after this we're going to say res. end awesome and of course we need to export our IO Handler so export default IO Handler this is what we need to do now we can head back into our socket provider which is in here socket provider and now we can just continue with what we were doing after this we need to say use effect so we're going to create a use effect here set this to an empty dependency for now and uh what this is going to have is const Socket instance equal to new um and we're going to import client IO so this is basically IO but it comes from the different package go down here and say import IO as client IO from socket IO client go down here here and we're going to say client IO as any and uh we're going to go ahead and in um invoke this to and we need to say process. environment. next so I'm just going to go to my environment file and copy this CU I don't want any issues here we need this uh URL okay so if you haven't put this in here it's basically Local Host which is the you know this one right now and it'll be updated when we're deploying that's that's it okay so close this come in here and next public site URL and we're just going to put this um right here and then we're going to uh pass in some other options so for this one we're going to say that the path is going to be SL API SL socket SL iio okay and then add trailing slash is going to be false okay just like this I hope this is ADD trailing slash yep okay this is correct and after this so we have this bracket here so after this we're going to say socket instance cuz we created the socket instance here and we're going to get the connection okay so we're going to say on connect then we're going to pass in a call back function like this so on connect we're going to say set is connected true uh to True okay just like this what about the disconnect so let's go ahead and do that too so socket instance dot on a disconnect we're going to basically pass in a callback function in here and this one is going to just set is connected to false okay very simple so if you ever need this you can just use it from here okay you don't have to do anything crazy and create new socket in instances in every application and then we're just going to do a quick clean up in here too so we'll just say socket instance. disconnect okay and you want to go ahead and invoke that awesome and now let's make sure to return our socket provider so let's say socket context. provider and in here pass in our children we need to also pass in the value and the value is just going to be an object with the socket and is connected just like this awesome great job now we can use the socket in our application okay so let's go back to quill so shrink this Source um components quill editor quill like this and now we can use this here so let's go all the way to the top Hooks and we're just going to say const socket equal use socket and just import it and now you also need to go to your app folder so go to app main or you can just go into this layout actually yeah you don't need to go into main sorry about that and in here we're going to wrap our entire component in that in that socket provider so go in here and just say socket provider and pass in the children just like this and also the toaster so I'm going to go here and just pass in the toaster like this I quit this and go back to our component Okay cool so now I just want to point out something that's happening here so basically this right here these details is going to swap between what we have locally and what we have from the server correct but initially it's going to set the data to what we have from the server now if we made a change to to our um to our server because of the router cache it's still going to have the same data because the directory in the directory that we have locally so we have saved some data in our state right that state is still going to be the old data so I want you to think now what are we supposed to do to update this data so that it can use the new local state it's very simple we need to Simply create an onchange Handler for our quill editor and that onchange Handler is basically going to um update our local state and it's also going to send all the events to the other clients and things like that so that they can receive everything so we're going to separate the logic first and we're going to first do it uh for updating the thing okay so we're going to refetch the data on every cach so we're just going to refresh it on every um change I'm sorry on every time we load this component we're going to refresh the data with a new API request and the reason is because if some user made a change if some some other user made a change we need to update the data data that we have so we need to make that API request in here that's what we need to do and a quick note here the reason why we cannot use So eventually we'll be building our Ed real time hook okay to set up all the workspaces the folders um the folders the files and things like that okay so the reason why we're not going to use that is because if another user made a change and we're using socket.io to broadcast those changes we're going to end up broadcasting changes and we're also going to end up receiving changes from the database it's going to kind of conflict in a way right so that's why we're not doing that exactly and um here that's why we're going to basically use a use effect hook to make this happen I just want to give you guys a quick overview so you actually know what you're writing and um that way it makes more sense okay so I like to put my use effects hook use I like to put my use effect hooks all the way at the bottom so it's just easier to read so go ahead and say use effect invoke this pass it a call back function actually an empty dependency for now and um what we're going to say in here is let selected selected directory and you see the pattern we're using this stuff again so you definitely want to put it somewhere else but uh I want to quickly look at something guys to make sure that I did the socket provider correctly um let me go in here real quick and our socket provider is inside our providers socket provider okay so there we go I realized we made an error here I was wondering cuz we never set the socket how are we going to get it so after this guys right here we need to set the socket to our socket instance okay and let me make sure okay the dependency is empty all right perfect now we can just go back sorry about that I just wanted to make sure so I'm glad we actually caught that right there so let's go back to our component so we're going to do selected directory and we're going to first check if directory type is equal to type of file okay go ahead and do everything with me guys just do it with me right now all right and um we're also going to create actually let's create a fetch information uh function like this that's going to do this for us so that way it's just easier and let's put it like this okay and this if all right awesome and this is going to be an async function and we can put all this in here so this is where we're fetching the information so we're going to say const um data and error and let's actually rename this to file um yeah we can just say selected directory error something like this is equal to await get file details and we need to pass in the file ID and we need to make sure that file ID actually exists before we get the file details so I'm going to say file file ID so I'm going to say if there's no file ID just return and file ID we need this in here okay turn and then here we need to check if there is any error or the selected directory um or we can just say if there's no selected directory then we want to actually push the user to the to the dashboard page so let's go all the way up top and let's use that hook so it's called um router so router equal use router from next navigation and let's go back down here and let's uh basically say router so return router. replace okay we don't to user to come back to this page SL dashboard because it turns out there's no file that exists like this so we need to send them back also we need to check if there's no selected new no selected directory at zero then we need to do router. replace and send them back to slash dashboard slash um this is going to be a dynamic string actually so slash dollar sign we're we're going to say workspace ID okay so since we need the workspace ID in here let's pass in the workspace ID in here and inside this we want to make sure that the workspace ID exists okay so we can do it right after this right here so if if no workspace ID then just return okay cuz something's happening weird in here so that's what we want to do and we're going to go ahead and send that and finally we can just return here and after this so after this if statement that we have right here here go ahead and check if there's no workspace ID um or up quill is equal to null so if we don't have quill in here then we you know it's not going to make any sense we're just going to return like this okay and if there is nothing in our selected directory as well so select the directory at zero do data like this so we don't have any data then we also want to return okay um and then yeah that that way we not we don't want to Route the user back we want to still keep them on the page but we don't want to do anything right and but if there is some data we need to set the contents of quill so we're going to say contents um json.parse and let's pass in our selected directory at z. dat just like this or we're just going to pass an empty string so we don't get any error here okay awesome cool and after this right down here we're going to dispatch an action and this action is called update sorry the type is basically update and we're doing files right now right yep so file with the payload set to the file it needs full file ID and it needs a couple other thing workspace ID so the file is basically going to be an object with the data set to um the selected directory so let's just do this why why not yeah let's just do this so we're just going to say selected directory at zero okay this is basically all of this so um it's just going to pass in that data so that should be fine okay and then let's look at the file ID is going to be the file ID that we need the folder ID is going to be this folder ID but it cannot be null so let's go ahead and say folder ID if you remember we already attached the folder ID to this files we can just use it right here so we can say selected directory at 0. folder ID like that and this is saying string or null is not assignable okay so it's because of this so if I remove this okay for some reason our data type is set to null here here um okay so the way to fix this is to go all the way back into your schema file inside Libs we have our superbase schema let's go into files which is right here and we have the folder ID right here which is a uu id. references this has to be not null it cannot be null how can it be null right and then let's copy this and we want to do the same for the workspace ID just like this not null and let's go up top here here same thing for our folders We have the workspace ID let's put not null there so go ahead and just do npm run generate okay and then do npm run Dev we already need this I'm just going to refresh this and say Dev and let's refresh that so hopefully it can migrate those new changes that we have okay looking good so far okay we're having some socket IO issues oops we made an error in our client component let's go back to our provider socket provider and say client like this this okay all right boom there we go nice everything is updated um I also want to go to our database and make sure so I'm just going to refresh this go to table editor we need to go to file actually we don't even have to do that what we could do is we could just do npm run pull if you'd like so npm run pull and we need to update that so don't forget so go into our schema go to subscriptions right here copy your subscriptions go to your migrations schema and you're going to have that error here so I'm going to go to that error and I'm just going to re like replace our subscriptions with the new stuff all right awesome and then let me check in here super based types of course guys you can go ahead and download the types as well so that way you have updated types so actually let's do it right here why not API scroll down click on generate download types and then it's going to open a file so I'm just going to go ahead and open that file up copy everything in here close this file go into to your types and replace everything that's till this Json right here okay close this and um that should fix that error so we can go back in here and now you can see all right boom there you go that's fixed all right guys so the error you were facing here is because of some values I could be undefined and all that kind of stuff so what I did was we I just realized we don't even need this details here right so I'm going to remove it so go ahead and remove the details from this component and inside your banner upload form the details were also in here so I went ahead and removed that and removed it from our uh props as well okay so we're not going to have any errors anymore so let's go back here close this and that should fix it so remove that boom there we go all right all good all good to go okay so let's go back to what we were doing which was right up top all right guys so I'm also going to change this just to the data cuz I don't want um anything else to change cuz everything else is real time so what I'm going to do here is I'm going to set the data to be equal to this one. data okay I don't want to Res reset every single thing because our payload is going to need some other data right so let's just do this here and this should be good you can also pass in the whole thing if you want to but I just want to make sure we're changing the things only changing the things that we need to right awesome so after this we have the workspace ID we have the folder ID which is the folder ID from that from that selected directory and let me go down here real quick so after this um after this green bracket right here we're going to now do it for the folder so if directory type is equal to type of folder then we're going to do something in here okay so um what we're going to say is const data and then we'll say selected directory and then error and then we're going to set this equal to await get folder details and we need to pass in the file ID just like this okay and um let's just update that awesome cool and then after that we want to check if there's an error or there is nothing in selected directory okay if so then we don't want to replace I mean we don't want to return we want to actually return the router. replace um right here and we want to set this to the dashboard like this so dashboard just like that okay awesome and then after that if nothing is in the selected directory at zero because this is the an array here it's the same thing guys okay you can just copy paste and change the API request as well I'm just I just want to type so you guys can also learn um and see what's happening so if there's nothing in here we're going to send them back to the dashboard SL dollar sign and you want to say workspace ID just like this awesome okay and it's literally the same thing so I'm going to copy that um the rest of the things and I'm just going to paste it in here you can go ahead and copy and paste to no problem okay copy it from here paste it in here and our action is the only thing that's going to change so we're going to dispatch a new action in here with the type set to um update folder okay and the payload is going to be something else so the payload is going to have the folder and then what else the folder ID right so we'll get the folder ID and the workspace ID like this so the folder ID is going to be the file ID so the file ID from the uh from the our props the folder itself is going to have data set to our selected directory um at 0. dat like this okay and then the workspace ID is basically going to be you can just pass in workspace ID and you can do a check here or since we already attached it to the folder itself we can just say selected directory at zero . workspace ID like this okay awesome and then after this dispatch right here we're going to do it for the workspace as well so take it up as a challenge and build the um the workspace condition so we did folder we did file go ahead and do it for the workspace pause the video and come back awesome well hopefully you got it right but this is what you have to do if you made any mistake or whatever so um you want to check in here right to make sure there's no error so I'm going to put that in here cuz I actually didn't do that so we'll say if there is an error okay like this um we're just going to return here we're not going to do anything crazy here so if there's an error or there's no selected director we're going to return because this is the only thing we need to do here because there's no workspace okay and um or you can actually you can just send them to the dashboard page this is fine yeah if there's an error send them to the dashboard page and the dashboard will tell what to do from there whether to create a new workspace or to send them to one that exists okay and then if there's no uh select the directory quill is equal to null return if there's no data you want to return and then we want to set the quill to that to that data and then we also want to dispatch a new action here called update workspace we're going to set the workspace to be equal to the whole directory and you can change this to also say data is going to be workpace um sorry selected directory at 0. dat like this okay just like this so this looks good and um that should work exactly as expected and of course you have to fetch this function so go down here and fetch the function just like this okay awesome and some things need to be passed into this dependency array the quill the workspace ID file ID and let's also pass in the directory type cuz we're going to need this and I think that's that's all you need yep that's all you need for for now okay cool and let's move on to the next part all right next we need to create rooms for um our application so whenever this page renders this component renders we need to create a room so it's actually really simple so I'm just going to say use effect like this and um this one is going to need our socket quill and the file ID okay we need these things in here and in here you just want to say if the if the socket is equal to to null right socket equal to null um or quill equal to null or um even the file ID does not exist so you can just say not file ID you can do the same thing for everything that's fine then we're just going to return okay if not we're going to do socket. emit okay and we're going to emit the create room event right here and pass in our file ID awesome so refresh this and boom that works great and also let's make sure so we would have had an error if it's not working okay the emit not working would have had an error but it looks like it already created it but if you want to test it out you can just say uh is connected which comes from our socket right here right socket provider so is connected and you can go to the bottom here and you can just let's render this out is connected uh what does it look like so if is connected we'll just return a div like this if not we'll return something else um or you can just yep or you can just say string connected or not connected let's refresh not connected connected boom so our socket.io is working so we're good to go okay awesome now let's move on to the next one all right so this use effect is to send the quill changes okay to all clients so we're going to broadcast something in here so this is where we're going to use our socket. iio our socket client okay so we're going to say use effect like this and um we'll come back to dependencies in a second because I don't know what we need and if the quill is equal to null so we're just going to do a quick null check to make sure everything is good um in here so I'm removing this I'm just going to say return if quill is equal to null or we also need the socket so socket is equal to null or the there's no file ID or there's no directory type um actually we're always going to have directory type so we don't even need to check this um and we're going to say if there's no user okay so we need a user here and we're going to get the user from our superbase um user if there's no user or there's no U cursors and this is something that's working progress so we'll get to this in a second okay so let's go up top right here and let's say const users user equal to um use superbase user awesome so now we have our user so let's go to the bottom where's our use effect right in here there's no user so pass in those dependencies so right now we need all of this so I'm going to say quill socket file ID um what else do we need the user we need um details as well cuz oh yeah we might we might use the details in here right of course so we're going to say details and I think that's all we need actually and we'll come back to the cursors um in the second okay so if this is the case just go ahead and return that's what we're doing right here we're just returning and after that um we want to say const selection uh change Handler okay and this one is going to be for the cursor so let's go in here and we're going to create a work in progress flag cursors update okay like this okay and then we need to create the quill Handler so qu const quill Handler and this quill Handler is basically a function as well and this one is for the changes to address all the changes okay so we can do this I'm just going to actually we can just keep that there no problem so what our quill Handler is going to get is the cursor the cursor I sorry not the cursor it's going to get the Delta which is going to be any for now and the old Delta which is also going to be any and the source okay Source any but this these two things we're not using I just wanted to show you that you can also get the old Delta in here if you want to do something with it okay the source is something that we will use though okay so um this you can also set this to an underscore but I just wanted to show you that this is what this does okay so if the source is not equal to the user then we want to return so what we're doing here is if the user did not create this change we don't want to do anything okay but if they did then we're going to save this in the database because that's an active user change so to save something if you guys remember we did debouncing somewhere right so we're going to go up top and we're going to create our save timer ref okay so just say const save timer ref equal to use ref and this is going to have a return type set to type of set timeout go all the way back to the bottom and in here we're basically going to use this to save okay so we're going to check here if the savetime rf. current exists if it does clear the timeout okay save timer ref. current so go ahead and clear it and then we're going to say set saving um which is we just created that so set saving to True okay so now when we're making a change um first we're going to do this and then we're going to set saving to true just like this okay so then after this you want to say con contents equal to quill do getet contents so let's get everything from here so quill doget contents like this and then we want to also get the length of our of the quill so we're just going to say quill do uh quill length is equal to quill doget um l n GTH so get length like this sorry not this yep uh we need to get the length and then we're going to say save timer ref. current is going to be equal to set timeout invoke this pass in um this and we're going to actually set this to about 850 uh milliseconds like this and in here we're going to say const update State this needs to be an Asing function also because we're going to save right so we're going to say update State equal to um a function a call back function just a function like this sorry this is going to have a dispatch so we're going to invoke dispatch and we're going to say type is going to be update okay so depending on update folder file or whatever you would have to pass it in here so what we're going to do is uh let me just think real quick let me see what's the best way okay so instead of just creating this here I'm just going to do it inside this function itself okay so we're going to say if contents and quill length quill length is not equal to one and we also want to make sure our file ID exist then we're going to do the following so um we actually don't even have to check but um okay it's fine we'll just check in here okay we're going to say if the directory type is equal to workspace then we need to do something if not we'll do folder and file like this okay so for folder first we're going to dispatch something so we're being optimistic here and we're going to say update the sorry for workspace update workspace payload is going to be set to an object with the following stuff in here so we're going to have the workspace which is going to be an object with with the data so let me just think what are we going to pass in here um so yeah we have to set this data to json. stringy and we have to pass in the contents just like this and the workspace ID here um needs to be the file ID so just like this so workspace ID is going to be the file ID like this so once we've done this now we can go ahead and say update workpace and we need to pass in the um updated data so data is going to be set to json.stringify do contents contents like this and this is also going to need the file ID same thing for this guys go ahead take it up as a challenge it's super easy and go ahead and do it for the folder and the file okay all right guys awesome hopefully you got it right if not I'm just going to going to show you exactly how to do it okay so for the folder we need this workspace ID so I'm just going to pass it in here and make sure you also update the dependency array like this with the workspace ID and then we're going to return if it doesn't exist if it does we're going to dispatch this pass in the workspace ID the folder and the folder ID which is the file ID and then we're just going to update the folder in the database with data set to this value right here right here we're going to say workspace ID does not exist or folder ID does not exist go ahead and just dispatch this action um I mean return and then if not dispatch this action and pass in these values and then finally we're going to await um and update the file uh in the database okay awesome guys and after all of this right here we need to go ahead and set our saving to fault like this okay set saving to faults don't forget about this and after this part where we have this we created our set timeout we want to say socket. Emit and we need to pass in send end- changes and pass in the Delta that we get so Delta and the file ID like this okay let's make sure this is inside this function um okay I think it is and after this we also need to listen to the cool changes okay so quill actually gives us um some events we can listen to the first one is text change in here and we're going to pass in our quill handlers this is the quill change Handler basically and then finally we have another work in progress flag here which is for the cursor and this is going to use the selection Handler okay and then let's go ahead and return um so let's do some cleanup here and we're just going to say quill do off um and this is text- change and pass in our quill Handler just like this and also another work in progress cursors like this and we need to remove this um in here okay I just want to keep it there and then finally we can also check if our save timer ref exists um we'll check if if this does we'll also clear timeout um right here so we'll say save timer ref. current and just clear that timer if it doesn't um exist in there great job guys so now we are having all the data kind of synced up and if we make a change it's going to go to all data but you see here it says so if I make a change here right you see it keeps saying saving because it sent the data just like this you see that but if I stop boom it saved the data okay so that's all I wanted to show awesome great job guys so um let's move on to the next section now all right guys I think you guys already noticed this happening but basically if you make a change here header test like this you will notice if this is a workspace there is going to be a weird refresh the reason is because of the revalidate path for a workspace if you're on a workspace every time we are updating the workspace we're revalidating it okay and because of that it is refreshing the page go ahead and remove that and the reason why we can remove it confidently is because here we're no longer pulling in data every single time because we're also switching to local data so there's no need for us to revalidate the path and now if you go ahead and do it you're not going to see that flicker on the page and now let's quickly test um our states here too so we have this Untitled here if I change this guys everything should change in real time all right guys so I was trying to test this and I realized something in here inside our settings page we haven't actually completed it I just checked the work in progress tags here and I realized we need need to get the collaborators this is the settings form page create a use effect and we need the workspace ID check if there's no workspace ID and if not we're just going to return and then we're going to say fetch collaborators like this equal to an async function and we going to say con response equal to await get collaborators and we need to pass in the workpace ID so we don't have this so let's go into our queries which is inside superbase queries and we're just going going to say um export const get collaborators is equal to an async function in here we need the workspace ID which is going to be of type string so workspace ID string just like this and in here we're going to first um just say const response equal to await db. select from the collaborators table where equal to collaborators doid um sorry collaborators do workspace ID is equal to the workspace ID we just passed in if response. llength exist if not we're going to return an empty array um if everything looks good we're going to say const user information is equal to promise this is going to be a promise and this is going to be a user or undefined let's go ahead and set this equal to so remove this put this and then say equal to response. map async like this and this is going to to be user for each of this user we're going to check if they exist exists equal await dbquery do uh users. find first where this is going to be a callback function like this this is going to give us the user and also equal to user. ID and the user. user ID and in here we're going to return exists like this let me see what seems to be the issue isue in here oh sorry guys this has to be an array below this return we're going to say const resolved users equal to await promise.all pass in the user information and then let's return resolved users. filter Boolean as user array let's go back to our settings forms and let's get this data right in here and now we can do something with this after this we want to check if the response. length is true this is not a function sorry it's not a method so set the permissions to Shared because this means there are some people in here and then set collaborators to our response that we get from there and again let's just turn this back on so we can fetch our collaborators so after this um scroll to the bottom guys where you have the select here and this is not default value this is value here so now it's going to sync up and now let's go ahead and refresh this and I'm just going to go into a shared workspace I think this person also has access to that and if I click on settings there you go now I can see it's set to Shared when you change it to private basically we need to remove all these users right we can't we can't have them in there let's go back to our code so after this alert here guys we're going to use an alert dialogue to basically let the user no you're going to change a share to a private workspace so I'm just going to go to Shad CN and I'm going to install this alert dial dialog which is right here so now we can also import all these dialogue things I'm just copying this right here and I'm just going to paste it right here so we have the alert dialogue it's going to be set to a state and this state is called open alert message which we already have set and in here we need to have the alert um dialogue content then we need to have the alert dialog header inside this we can have the alert title so are you sure we can just put are you sure in here say alert Des description and in here I'm just going to copy paste this stuff okay so paste this in here changing a shared workspace to private will remove all collaborators permanently cuz you're changing it right so put the alert footer in here and then this is going to have an alert dialogue cancel so the onclick it's going to just have a call back function and this one is just going to set open alert message defaults and inside this we're just going to say cancel after this one you want to have a dialogue action so this is the the one where they really want to delete okay we're going to have an onclick and we're going to set this to onclick alert uh confirm say continue and let's go ahead and build out this function so right up here const onclick confirm and set this to a function and this function is going to be async function and what it's going to do is if there is no workspace ID then we're going to return if not we want to check if collaborators length is greater than zero so we want to make sure we even have some collaborators right and then we're going to say remove collaborators invoke this and pass in all our collaborators and then we also need our workspace ID cuz we can only remove it for a workspace ID and then let's set the permissions to private and then set open alert message to false let's go to our on select change okay so right here we're actually changing the value directly that's not what we're supposed to do we need to pass in a function and we're going to call this function um on permissions change and let's go up and create this function too const this is equal to a function just like this and in here is where we're going to do that stuff okay so we're going to check if value is equal to private then we're going to do something and this value comes in from that onchange Handler guys okay we're going to set the open Alert state to true so we can show them dialogue and if not then we're just going to set um the permissions right here to the value so if it's private we want to do this and then in here we're going to do that logic click on the settings and it's showing the shared workspaces if I change this to private it shows this I can't click out because it's an alert message if I cancel we're good to go but if I hit private and then hit continue it goes ahead and it removes everyone from there so now if I refresh this again and click here now it's a private workspace this part is a challenge for you but don't worry about it I will give you a good example of how you can set real time sharing to kind of refresh um you know or change some states in our users in the other users too so Avatar details it looks like here we had one more and I already did this I showed you how to do it with the help of superbase storage so go ahead and give this a shot it's the exact example um that we did inside Banner right how we pulled a banner for our workspace all right so let's try to share this test workspace with this user okay since it's not real time setup it's not going to update we have to refresh so let's go ahead and change this to shared and let's add this user in here and now it should work okay so if we add Joe okay so that is not updating we need to take a look at what's happening guys so um let's look more into this okay okay so I tested this real quick and we need to still make a couple more updates so right in here this needs to change to private and then when we add a collaborator guys this was actually collaborators initially but that's not how it's supposed to be cuz we're going to end up adding all the collaborators to the list so we want to just say the profile we don't actually need this router. refresh I think let's let's see okay let's just refresh this let's open this change this to Shared let's add Joe in here so we say Joe cool he's added boom it's done Let me refresh this page again open settings and now we see Joe in here okay so if I refresh this I should see the test in collaboration okay right there so now I have access to this too if I remove this if I remove Joe from here now you see there there you go okay I don't have access to that workspace anymore so we already have our um socket emits here to send the changes but we have to also receive the changes right so that's why if you type something in here it's going to save but it's not going to emit it to all our clients so let's go ahead and say use effect let's go ahead and provide these okay cuz we're going to need this uh which is a socket Quil and file ID Quil is equal to null or socket is equal to null we're going to return and then we're going to say const socket Handler is equal to a function this is Deltas which we're going to get from our socket so we're going to say Delta and this is going to be any and then ID which is going to be string and inside this we're going to check if the ID is equal to our file ID um then quill do update contents to the Deltas that were passed in and then we just need to say socket. on receive changes and I'm going to pass this in here okay and let's just quickly just return um a cleanup right here so we're going to say socket. off receive changes and we want to pass in the socket Handler like this now let's see if this works so let's refresh this refresh this data as well and now if we make a change okay so it does not seem to be sending the changes which is upsetting but um I'm going to go ahead and debug and then I'll let you guys know all right guys so I just did a quick test and turns out that the issue is we put the receive Handler inside the socket so just bring it right outside it okay and now if you make a change there you go it updates on all um all your clients and if you go into another workspace let let's say we go into this folder okay just to make sure that it emits it to the right folder ID if you make a change in here it's not going to show up in here okay if you go back to the workspace all the data is um you know it is synced and if you go into a different page and go back into the workspace it has the new data this is why we have to set up that new fetch request okay so if you guys remember I spoke about the modules right here right the modules option which um allows us to create our own custom modules that we can put in here right that's what we're going to do here we're going to use these modules to basically create cursors and these cursors allow the user to see what someone else is selecting where their cursor is and you know something like Google docs for example so go ahead open your terminal quit the terminal like this and write npmi quill dasc cursors like this and go ahead and hit enter so right here we need to say quill cursors we need to import this so we're going to say await import quill Das cursors like this and uh we're going to just say default and here now we need to register actually right before this right after this we need to register that new module so we're going to say quill do register and we have to register this new module which is slash sorry which is modules like this slash cursors okay and then go ahead and pass in your quill cursors that we just created right in here awesome and now in here you can say cursors like this is going to be equal to transform on text change and set it to True first thing we need to do is actually create these cursors for each of our users so when we're doing this we need to actually um get um you know custom avatars for our user and we also need to use uh real time presence from superbase to actually show the cursors for each of these users okay and also to show the states of the users right up here okay to show who's collaborating on the document right now it's just showing one user so we need to actually show who's collaborating on it go to the bottom where we have all our use effects right in here and create another one like this and set this to an MD dependency for now and then we're going to say if file ID does not exist or quill is equal to n n then we're going to just return like this return out of this if not we're going to create a room okay so we're going to say const room equal to superbase do Channel dot um actually sorry invoke this and pass in our file ID so since we need these two things let's go ahead and say file ID and uh we also we might need the quill right we're going to need quill in here and you can also pass in super base CU we're going to need that as well right below this we're going to say subscription okay subscription and this is equal to room.on invoke it and you want to say presents and after this you want to pass in um event of sync and this takes in a callback function and this basically gives us access to all the all the stuff okay so after this we need to say const new state equal to uh room. presence State like this and then we want to say const new collaborators collaborators is equal to object. values because this returns a very different type of State okay you can console and see what it looks like but it returns a bunch of stuff so we're going to say this one. flat because we only want the values and only the users and we'll just return this as any because there's nothing in here yeah so we'll just return it as any no problem and then in here we need to set our collaborators to to the new collaborators just like this so right now if we go up to our collaborators we have one default collaborator right in here so let's go ahead and remove this default collaborator and let's go to go back to the code and after setting our new collaborators we want to check for our user so I think we are already importing user from um let me see okay from superbase so that's good um let's go back down to the set collaborators yep right here so if the user exist all cursors which is going to be of any is equal to an array and then we're going to say new collaborators do4 each okay for each of these we want to basically get the collaborator like this and for this one we're going to extract a couple things from this collaborator so we're going to get ID U sorry we're going to just give types for this right ID is going to be string email is going to be string and Avatar R like this is going to be string as well okay okay so I have to put this in I don't know why I didn't do that so we're going to do this and then we're going to set that to a function okay so in this function we're going to say if the collaborator doid is not equal to the user. ID then we're going to say const user cursor equal to quill doget module and we're going to get the cursor cursors like this and then we're going to say user cursor. create cursor so we're going to create a cursor for this user and we're going to pass in the following stuff so collaborator do um ID okay and because so if you go and look up the documentation this first requires an ID for the uh um the cursor and then it also needs like some other information so we're just going to say email do split this is basically the um the name that's going to show up for the cursor if you hover over it okay so we're going to split it at the at symbol and then we're going to take zero like this okay and then finally it needs a color so I'm just going to do something random here I'm going to say hash math. random. random and then this. TW string invoke that and we're going to pass in 16 in here and then SL slice so slice like this and we're going to get two to 8 so this is just going to create a custom string for us guys okay so what seems to be the issue here string has no signatures okay so we made a small mistake here put a comma and then hit enter and after this here all cursors do push our new cursor which is a users cursor okay so we want to make sure that we're only pushing in our users not our users cursor all the other users cursors okay after this guys right here you want to say set local cursors which we're going to create in a second cursors like this to all cursors so let's go up and let's create the state which is const so local cursors is equal to use State like this we're going to set this to um just an mty a we'll set this to any okay there is a type called cursor but I found that it's just doesn't work right something is wrong with it so that's why I just you know never worked with that just said whatever subscribe to this room and you want to this basically gives us a function so we need to get the status here and we need to check if the status is not equal to subscribed okay or there's no user so we need these two things if this is the case we want to return if not we're going to do room. track and we're going to pass in an object with the ID set to user. ID with the email set to user. .split and we're going to split it at the at symbol we're going to take the first element and then finally the Avatar URL is going to be user. Avatar URL and we're not going to have this I'll tell you why we're not going to have this because this user is going to be something else okay so just give me one second I'm going to show you guys what you need to do okay Avatar URL so so what you could do here is you could make an API request to get the user information and then you can pass it in here okay so for that you will need an async function here or another option you could do is you could reset the users right the user that we have and you could kind of create um like a different a combination of two different user data so this user data and you can pull the URL from somewhere else okay so I'm just going to do it in here actually so what we're going to do is um let me see if we have find user that's the that's what we need right so we already have the user ID here all I'm going to do is change this to an async function say const response find user okay I don't know if we have this but we should have it somewhere let me check what we're doing in here oh we just did it right in here okay so let's go ahead and create that okay really really quick so go into Libs superbase queries and just create something here called export const find user just like this and this is going to be an async function I'm just going to shrink this so you guys can see more async function and this is going to need the user ID which is going to be a string and this is just going to we'll just do it right here okay const response equal to await dbquery do um users like this find first like this and we need to say where or we can just say user and then we get equal to here here we're going to say equal to the user. ID is equal to user ID that we passed in and then we're just going to return response like this and then we need to say find this user invoke this um invoke this function and we need to pass in our user um ID in here so user. ID just like this and then we need to make sure the user exists here too so we're going to say if no response we want to return okay cuz we need all this data and then in in here we want to do this like this so we'll check if the response. Avatar URL exists and if it does then we'll do something okay we'll do something here if not we'll do something here so the first thing we want to do is super base Dot storage. from like this we want to go into avatars I think that's what it's called we can just look in here real quick avatars like this. getu URL just going to save that and we're going to say response. Avatar url. dat dopu URL so we can kind of sync it up after this we also want to uh yeah if nothing exists we can just return an empty string that's fine cuz we have a fallback right if you remember we have that fallback there so that should work correctly and now we also need to get this user so um actually we don't need to get yeah we already did it in here so we already got the user okay let me we just check to make sure everything looks good and then here you just want to return um just a cleanup so we're just going to return a function say super base. remove Channel but not all Channel remove Channel and we want to pass in our room okay so um we also need to provide user in here okay cuz we need this user to actually create this and now if you go in here and refresh this let's see what happens boom there you go it shows two people join if you leave this immediately it will go ahead and disconnect so if I join it will go ahead and add the user if I leave it's going to go ahead and remove the user so if you hover over their name you can also see the username here but we didn't we didn't actually put that so let's go ahead and uh add that this tool tip content right here and you want to change that to collaborator doil if you hover over this person you can see who that is and you can also see the other users too now we have our user set up um let's continue to work on our cursors cuz we already also created the cursors that we needed we have the selection change Handler so I want to quickly just tell you what this does and then we'll jump into it okay so this the selection change from quill basically fires when they click on on this um on the canvas you can say or the editor and if they select anything so when a selection happens it returns a range from start to finish and we need to send that range or where they selected to the um you know um to all our clients so that's what the selection Handler is okay we have the onchange Handler now we need the selection Handler so this gives us the cursor like this cursor ID which is a string so we're going to go in here and we're going to return something okay this is going to be an arrow function like this and this is going to have the range in here which is going to be any for now and the old range which is going to be any and of course the source okay s o rce which is um any again so this Source we need to check to make sure it is from the it is not it is from the user so we're going to say Source equal to user and we need to make sure the cursor ID exists not user ID cursor ID exists and if both of these are um true then we want to emit that so socket. emit the send cursor move um event and then we want to pass in the range the file ID and the cursor ID just like this so if we go to the bottom here uh we have this quill Doon so we want to say quill Doon and now um for the selection change event it's called selection change okay like this we need to pass in our selection change Handler and we want to pass in the user. ID because this is what the cursor ID basically is okay so now we can remove this and and finally we also need to quit we need to you know turn this um off so we can remove that and we can just say selection selection change Handler awesome we also need to listen to the changes okay right now we are only emiting the change but we have to also listen to the change and we can do that by simply creating another use effect in here with an empty dependency for now and then we're going to just do the same check guys the same type of check here we're going to check if quill exist if not you know and uh we also want to check if the cursors um have some length and then we want to say const socket Handler equal to um just function like this and this will give us the range okay which is any and the room ID which is going to be a string and the cursor ID which is a string as well okay just like this and inside this we're going to do a couple things so first we want to make sure the room ID is is equal to the file ID if so we're just going to say const cursor to move is equal to local cursors doind just say C which is going to be of type any we're going to say c. cursors and if this exist we're going to get at zero and do ID equal to cursor cursor ID like this okay so we're just searching for um that cursor like this and then after after this so after this part right here we're going to say if cursor to move so if this exist quick heads up in the next video we will be building the best application on YouTube yep that's right because the next application is going to be built by you we are going to be using the comment section to determine what features to have in the next project so go ahead and comment below what feature do you want to have on your project and we will make it happen so don't don't forget to subscribe to get notified when that awesome video comes out and please drop a like on this video to support your boy so that I can provide more free value just like this then we're going to say cursor to move. move cursor okay and we're going to move it uh move the cursor ID so that specific one to this range so we want to say receive cursor move this is the action this is the event we're listening for and we have to pass in a socket Handler like this and then here we want to return just a call back function to do a quick um um cleanup okay so socket. off invoke this pass in that cursor move and then pass in our socket Handler just like this awesome and we're going to need some dependencies of course so first let's pass in the Quil socket the file ID and you're going to need the local cursors okay don't pass in anything else it's just going to create unnecessary stuff here all right so let's go back to this test workspace so now if you see you can add their cursor is actually going to update so Prodigy's testing the cursor is actually updating and if I hover over this you see it's showing um Joe as well so Joe is right here and if Joe makes a change in here and he says hey I'm making a change you see it's also showing Joe's cursor okay and this is my cursor so I can also edit as well how awesome is that looks super cool right so before we move forward let's also just quickly build out our mobile sidebar so after this go ahead and return a new component called mobile sidebar like this we don't have this yet but we'll get to this in a second okay and you want to go ahead and say sidebar like this cuz we're going to return the same thing but the params um I mean the pams are going to be set to the same params here and we need to provide a new class name to give it some better styling so width is going to be screen inline is going to be a block and then from SM it's going to be hidden okay we're going to hide it from small devices and this can just be a closing tag and since we don't have this go into your components and in um in your sidebar you can create this component if you want it actually makes sense to put it in there so let's say mobile Das sidebar like this. TSX and say RAF CE and just paste this in here now what we're going to do for this component is first let's go ahead and provide the interface and it's just going to have children so I'm just going to copy paste this and it's just the children and this is react act. react node and uh we're going to have two navigations okay so I'm just going to create a const just a variable here so const called navigations and I'm going to set it to these okay which is the title sidebar ID sidebar and this is going to be something like this and then the title is going to be Pages for this ID pages and custom icon is pages so let's go ahead and import this this is also in the GitHub repository if you haven't already but it's basically the icons that we we built in here okay so let's go ahead and import this so menu comes from uh from Lucid react and this Cypress page icon is what we have from our icons okay all we're going to do is just map over this and then we're going to create our states so quickly let's say selected nav and set selected nav and this is going to be a use client component like this and this is basically just going to hold the state of what has been clicked what is clicked at the moment okay so we're going to set it to an empty string and this is going to be actually pretty quick so we're just going to return a react fragment first and we're going to say selected nav okay is equal to sidebar so if it's equal to sidebar then we want to return something so we're going to return the uh fragment like this okay and inside this we're just going to pass in the children okay so only then we're going to pass in the children if not we're going to return something else so here you want to say react functional component and pass in the new props that we just created mobile sidebar props like this let's get the children from here too so children and this this will no longer throw this error okay cool and after this so after this you want to say nav inside this passing some class names okay so we're going to say BG Das black divided 10 like this backdrop Das blur and LG so large from small devices is hidden fixed and then it's going to be Z of 50 bottom zero right Z left zero so create this unordered list and this unordered list is going to have Flex justify between item Center and P4 and inside this we're going to say native navigations do map for each of them we're going to get the item and we're going to return something so what we're going to return is just an A List element like this and let's give it the following class name so Flex we have to say items Center then flex-all justify Center okay just like this and let's also give this a key um which is going to be the item. ID and inside this we're going to basically render the sorry not like this it's the item. custom icon okay so render that icon and we're going to say small in here and then we're going to give it the following class names this is basically the the the title or like the name for that uh for that element okay this is going to be right at the bottom guys it's kind of like a navigation you'd see on applications all right so import clsx like this okay first we're just going to do this and then for this one we're going to say text- muted D foreground is going to be if selected nav is is not equal to the item. ID okay then we're going to return this um this text muted foreground okay and inside this tag you want to render the item. tile perfect so it's not not too complex right that's that's pretty much about it for the mobile sidebar and let's refresh this and um let's see how this goes all right so we have this here and also I went ahead and just put some um default data guys so you can see how the new um the new nav that I created here not nav sorry the toolbar options you can see how it sticks to the top and it has this cool glass morphism effect which we also learned in the figma video so if you want to learn how to create beautiful designs like that I'll put the link in the description go ahead click on it watch it and um hopefully you learn some new stuff so there you go you see we have that sidebar at the bottom so if we go into our mobile sidebar we need to actually be able to click on this element so here we're going to say onclick is going to be equal to we have to set the new state right so set this to set selected nav is going to be item. ID if I click on this let's see so right now we have this boom there we go it shows up and because of the styling we have on our navigation our users um data has been hidden here and that way when we go into settings we'll be able to change the users data right here okay we don't want that component to show up at the bottom here just going to take up too much space and also on mobile devices it's actually Zoomed In by 150 so this is probably what it would maybe 150 or 125 I think 150 so this this is what it would look like on real mobile devices okay you can shrink this if you'd like to um I think something is wrong here uh let me see item Center um something is wrong with the flex box but yeah it's just it's just something with a flex box let me see what okay yeah there we go so Flex like this and that should solve that problem so I'm going to go ahead and refresh all right there you go centered now so if I click here Pages click here sidebar it um shows everything so I can navigate from here now if if you click on your sidebar um folders dropdown okay the folders drop down list you'll see um a a typescript error here and it's asking for logo so it turns out in our migration schema we still have that okay for the folder so I thought we already removed everything why is it there I'm not sure so let's go into folders and files and search for logo okay removed from here okay there we go so let's remove logo for that and let's quit this and yeah NP M run generate and then npm run Dev just like this and let's refresh this and that should actually update that in the database and you can go ahead and do npm run pull here once this is done okay it's oh it's migrating a lot that's that's probably why we're having that issue guys it's because every time we use a database it's creating like you know 10 15 entry points so that's um there's something wrong there so go ahead and do pull here I'm going to quit this and do npm run Dev one more time and uh let's take a look at it okay and because we did pull we have to go ahead and update that subscription so I'm going to copy the subscription here go into schema file search for the error which is around here and just replace this okay now that should fix our issue let's refresh the browser now we're going to work on the real time um setup for um our application so basically between different clients if someone adds a folder we need that to show up so how do we do that it's actually very simple it's just very repetitive but um we're going to go ahead and do that right now okay so go into your Libs folder right here and create a folder called hooks okay um hooks like this and inside this you want to create a file called um use super base real time okay. TSX just like this okay and in here we it's basically like um a hook that we're going to create to attach to our folders component so that it will keep track of all the folders and all that kind of stuff okay so go on top go on top and just say const use um super base or we can just say rafc for Now Yep this is okay we can just do this and then we'll update it in a second okay so this return is not going to be div it's going to be null let's save that and um what we want to do here is we want to say con superbase equal to uh create client component client like this and we can also say const um dispatch because we need these things from here because we're going to set the state right State and workspace ID and then we're going to set this to selected workspace and this is going to be equal to use app States invoke this let me hide this so you guys can see more and then we also need the router so router equal to use router okay and everything is going to happen inside this magical use effect okay this use effect is going to do all of the real time setup for us um and we're going to do this right now so in here we're going to first create a channel so we're going to say const Channel equal to superbase do Channel invoke this and say db. changes okay just like this and since we need superbase go ahead and pass in superbase and here so the first thing before we do this I want to show you something because um this is important so go into your super base go into um let's see where is that I think it's under yep so go into database go into real time or where is this it's replication go into replication click on two tables here and we need to turn it on for uh we need to turn on the real time setup for our folders and our um our other stuff that we want okay so we need files folders and workspaces is kind of like a challenge for you so I'm going to set that up to you okay um we can you guys can make it work it's the exact same thing okay so go ahead and take that as a challenge and make it work also the answers are in the Discord if you need everything we're going to help you guys out so don't worry about anything um you can also turn on sure you can turn on collaborators if you need um these things you don't really need them that's fine okay now go back in here so now it's set up so real time is set up um so you can actually listen for changes so now you can say on and in here we want to listen for postgress changes okay and we want to pass in an object here which is going to have event set to Star okay so for all events we want um the schema to be sorry the schema which is right in here why is this not showing my schema schema is going to be okay it's not showing that's weird so schema is going to be public and the table is going to be files okay because we're going to first work on the files so on this we need to do something so this needs a callback function okay like this and this callback function will be invoked every time there is a change done on this table okay so first create a channel and this on is all you need to create another um another listener okay so on the Publix uh public folders on public workspaces so on so forth okay what we're going to do in here is this is going to give us access to the payload so first let's make this async because we might need some stuff so we're going to say payload and this payload is going to have um the following so we're going to say if the payload do event type is equal to so we have a couple here right so so we need the insert first then we're going to um just maybe console log you can you can say hey received realtime events people do this in real projects um so you can do it in here to print that into the console you want to create a new payload okay so folder ID is going to be um sorry we're we're just basically destructuring this from and here we're just going to destructure the following properties so we're going to get the folder ID which is the folder ID okay okay and then we need the workspace uncore ID which is the workspace ID like this and then finally we need ID which is going to be the file ID and then this is equal to the payload do new so this new property gives you the new data that changed okay and then in there after that we're going to check if there is nothing in state so since we need State we need to go in here and say State like this okay if there's nothing in state um actually we are not no that's not what we're checking here guys we're we're basically going to check if um we have that file what we're going to do is we're going to say if not state. workspaces doind you see we're doing this again right it's a great place to put it somewhere else but I'm just going to type it so that you can actually learn but I'm just going to copy this actually and paste it here I'll just read it so it's easier okay and uh what we're going to do is we're going to change this to ID Okay cool so so we want to check if this is true if this is true which is if workspaces doind um the workspace ID equal to the workspace ID the folders. find where the folder ID is the same thing and the files. find where the file ID is the same thing that just changed if there is nothing so we H we don't have that then we're going to add this file okay we're going to add it so we only need to add because um that's what we're doing right here right we're inserting so we're we're looking at adding addition so in here we're going to create a new file which is equal which is of type file which comes from superbase types and this is going to be equal to an object and we're just populating it with the data guys it's the same thing we' already done this before which is ID is going to be pay. new.id uh workspace ID is the same thing just get it from this okay pay. new get it from there create it at and all this kind of stuff okay pass in all this data and finally you also need the Banner URL is going to be payload do uh new DOT sorry new. Banner URL just like this okay so get all of these values I think the banner URL is going to be this Yep this is what it might be cool and then you want to dispatch an object here called type um of type add file okay and you want to pass in the payload which is going to be an object which needs the file something like this so let's just bring those in so we need the file um the file which is going to be the new file so we're going to say new file like this the folder ID and the workspace ID okay it'll go ahead and add it for us nice and after this we want to say else if okay the type payload do event type is equal to delete then we want to do a couple things so we want to say let workspace ID is going to be an empty string let folder ID is going to be equal to an empty string and then we're going to say const file exists so we're going to check if this file exists because we need to delete it right and I'm sure you guys already know how to do this but I'm going to go ahead and copy and paste so you can save you some time okay so what we're doing in here is we're basically saying state. workspaces do suum so if this meets once we want to get out of this do suum workspaces workspace folders. suum um folders do file do suum we're going to get this here and um then we're going to get the file ID equal to payload do old id okay because the old one that changed the workspace ID is equal to this workspace ID and um if this is true so if this is true we're just going to return true so we know that the file exists okay and then we're going to do file exists like this um and workspace ID of course and then we also want to make sure the folder ID exists okay if this is true so basically we set it in here right so if this is true only then can we say router. replace okay dashboard SL dollar sign workspace ID so we're just going to Route them because the user deleted this file so why do we have to keep them on the same page right we have to remove them from this page and then we're going to say dispat patch like this and we're going to put the type in here okay which is going to be called delete um here sorry guys this is delete file and this needs a payload which is set to an object like this so I'm going to bring in these I think there's one more oh that's it okay and the file ID is going to be the um the folder ID okay or we can just say payload do old.id okay and then um after that we want to pass in the folder ID like this um workspace ID all right so this is old.id okay for some reason an ID jumped out so now we're going to delete that file and finally we need to also do it for the updates right so else if payload do event type equal to update then we need to put in something in here so const folder ID we're going to basically um destructure structure these values folder ID and then we need the workspace um ID too so I'm just going to copy and paste you guys know the drill right so let's copy paste that and this is payload do new so that's how we get access to those variables and then we're going to again search for it okay it's the same thing the exact same thing so I'm just going to copy paste I mean not exactly the same thing but I'll show you I'll show you what is different okay just give me a second all right so it's pretty much the same but what we need to do here is we need to find that workspace the folder and the files Okay We're looping over them and we're checking if the file ID is equal to the new ID that updated okay and if so that means we have the file right we're going to dispatch an action here called update file we're going to pass in the payload we're going to pass in the workspace ID we're going to pass in this this and this um and the file that we want to update is just going to be um the title the icon if it changed and the in TR if it changed so if the user deleted it some other user or collaborator deleted it it's going to update for us as well done that's it for the files guys so we can actually go ahead and test this before we move on to make sure that everything is working and then we can do the folders uh and I'm actually going to leave the folders as a challenge for you it's the exact same thing but if not the answer is um inside the GitHub repository and it's also in the Discord if you need help okay so let me go ahead and um test this out real quick all right and I forgot one more thing we actually have to use this uh superbase real time so the best place to actually put this in my opinion would be inside the um the works inside the drop-down folders so let's go to that list which is folder dropdown list right here okay and let's go up top and I think I already have that set real time updates right here so let's import this and just invoke it like this okay so now it's going to do its thing so we have to go ahead and refresh okay we see some errors um what is the error let's see okay so use router has some issue let's go and check what the router is oh it's okay we imported it from next router it has to come from um the other the new package which is next navigation okay let's go ahead and refresh refresh all right perfect it works great now and let's go back to the test workspace here okay cool let's go ahead and try this guys so if we hit something here it should show well it's not showing so let me refresh this um and make sure all our real time data has been set and if I add one here it's not adding okay something is wrong let me go ahead and test it out real quick okay ah right here so for our super base right here we need to actually subscribe to these changes right that's that's the only way this can work and also let's return a um a cleanup so we're going to say channel do um unsubscribe okay so unsubscribe to these changes now awesome and also guys we might need um something else in here let me see selected workspace cuz we need that workspace ID so let's pass that in here so that can update accordingly okay and let's uh go ahead and test it out one more time and let's see what happens all right guys so I checked here we needed to change this DB from DB dot to db- changes okay and at the bottom you want to subscribe to this because that's the only way to listen to these changes and then we're going to return a uh just a cleanup function okay to do channel. unsubscribe and make sure you have the selected workspace in here as well so I looked at the database guys and the main reason so this even if you change this it doesn't matter you're still going to see the error because for some reason my files were turned off I even remember remember turning it on but the real- time database was turned off for files okay go to database replication click on Six Tables change it to whatever you want to be real time so we turned on folders files and um the workspaces too when you do the challenge and now if we go ahead and test it you can see I tested it quite some time but um let's just go back to this development page and if I add something in here if I hit add file it shows up for the other user to how cool is that and this user can also go ahead and delete this if they want to so um here's the other cool thing since this is real time if the user deleted this it's going to move it to trash and it's going to show for both of them if they were on that file so right now they're not on that file so they couldn't see it right but if I copy this link and paste it here this user can actually see this trashed file both of them can also restore it and it will show up right here as well great job guys if you have come so far I'm super proud of of you okay so the next challenge I'm not going to give you the answer um in the in the GitHub repository okay the answer is in the Discord if you need it but I want you to genuinely try you're going to set this up for the folders now okay so the folders right here when I delete a folder I want it to act like a realtime um database the same way we did it for files okay the exact same thing take it up as a challenge I'm going to put the link in the description click on it join and just ask me and everybody in there we're all going to help each other okay so inside our delete file Handler inside quill so go to your quill editor components and head over to your delete Handler so once we delete the file we actually need to Route okay we need to route back to uh the dashboard page or or the workspace page so since this is a file um I'm assuming the workspace of course is going to exist so we're going to do um router. replace and we're going to set it to a dynamic string say dashboard SL dollar sign workspace ID like this okay copy this and for the folders paste it in here but now you're going to uh actually it's fine for the folder too you can just route them to that so let me just do a quick little test to see if this works so if I go in here and if I delete this it shows up here and if I delete it right here um also you might need to reroute this user we let's see okay so if I delete it okay so I think that was handled by our realtime update okay so right after this alert right here inside your settings form components you want to hit enter you want to create a paragraph and give class name of flex item set to Center gap of two and margin top of six and inside this we want to say User it's a lucid react component it's just an icon and we're going to say size equal to 20 okay that's weird so I'm going to go up top and I'm going to to import user okay it's because hm this is interesting what's going on here okay so there's a clash here so let's just say user icon this has to say as and this is going to change to user icon and say profile okay and then after that we're going to use a separator component and then say div class name set this to flex items Center and then inside this we need the Avatar and inside this we need the Avatar image the Avatar fallback and this Avatar image component is going to have the following so the source user do Avatar URL which is actually not in here so you would have to do that API request all right guys I'm just going to skip over this because it's just unnecessary things you know how to do this we did it inside our quill editor okay but for now I'm just going to um set it to something like this just Source empty source and we're going to have the uh fall back right here and we're going to set this to the Cypress profile icon before this go ahead and create another div and set the class name to flex flex-all M left of six so we're going to say small with a class name of text- muted D foreground cursor not allowed CU we cannot change the email um and we're going to say user dot if user exists then user. email like this or just going to return an empty uh string let's use the label component HTML 4 equal to uh profile picture class name of text- smm text- muted D foreground profile picture in here input name is going to be profile picture just copy this so if we made any errors it's going to work and then type equal file except is going to be equal to image SL star the placeholder to workspace or sorry profile picture okay like this and the onchange is going to be a change which we're going to create so onchange profile picture disabled is going to be set to uploading profile pick now this is a challenge I want you to go ahead and give it a shot okay it's the same thing guys we've been doing this like 400 times literally we learned how to upload a banner we learned how to upload a logo so all you have to do here is get the user information okay like we did in quill editor get the user and once you get the user information create this on change and after that you're going to upload that using superbase if you don't know anwers in the Discord and answers also inside this okay I'll put it inside the GitHub repository after this div we're going to say log out button div class name Flex items and in here we're just going to pass in the log out okay which comes from Lucid react go ahead and create a P tag class name of flex item Center Gap to margin top of six so I'm going to import this component from Lucid react called credit card and then size 20 and Billings uh billing and plan and after this use a separator component like this and say p class name text- muted D foreground what's wrong here I think that's just some weird typescript error let huh weird I think it's coming from maybe this is causing it to fail so I'll just hide that all right that's probably causing it to fail so I'm just going to hide that okay and then after that I'm going to say this so from use superbase user I think we also have subscription in here yeah there we go we're just going to say if the subscription status is active we're going to say Pro if not free and then just say plan right here okay so inside your components go to Global components and just create something here and call it subscription dasm model. TSX then say rafc subscription modal like this okay and this is basically a dialogue guys and it has a dialogue and some states that we're going to use uh everywhere so um before we jump into this we also need our provider so let's go down here and go into Libs providers and let's say subscription modal provider. TSX and first we're going to create a type called subscription modal context type okay like this and this is going to be equal to an object with open set to Boolean and set open be equal to It's A dispatch from react set action so set State action from react and we'll pass in a Boolean and then we're going to say con subscription context is equal to create context from react the subscription model type that we have right here let's go ahead and say open false and then our set open is just going to be an empty function and then after this say export const use subscription model is going to be equal to this a function and in here we're simply going to return the use context for this which is a subscription model um model context like that okay go down here and say export const subscription model provider extract the children from here so I'm just going to say children is set to react. react node first thing we need in here guys is um the open and the close like this okay it's a state so open and set open equal U State and I'm just going to set false as the default value we just need to go ahead and return that component so just say return superbase Mo modal context. provider like this and we need to pass in the value or this is going to scream open and set open inside this component we're going to render out the children like this we also need the products and the products are going to be passed into our subscription model which we're going to get in just a second okay so let's go in here and say subscription model um let's see yep like this and create this component and that's about it so we're going to use this open and set open to kind of show this model so let's go back into the model and this is going to take a couple things so it needs the products to display right it needs some products to display so we're going to create that and then uh we're also going to create you know the option for them to subscribe and also um you know see the products and things like that all right so go ahead and say const open inside your subscription model this is equal to use subscription model like this and we also need the set open okay so that we can change the state and we're going to return a dialogue and this comes from UI dialogue and we're going to set open here equal to open from this state we want to say on open change equal to set open just like this and inside this dialogue guys we're going to return dialogue content going to render already on a paid plan this subscription comes from const subscription equal to use super base I'm just going to to kind of remove this say subscription if it exist subscription. status equal to active then if this is true we're going to render something if not we're going to do something oh sorry it's active guys not action here we're going to return the dialogue content if not we're going to return all the products and things like that so let's have the dialog header and this is going to have upgrade Pro Plan oh this has to be inside title sorry about that guys so dialogue title and now we we can put this in here okay so inside this component right here bring in our subscription model so bring this down awesome so now we have that in here okay and the products that I was talking about we're actually going to get the active products from this link right in here and then we're going to pass it down okay but um since we we don't have that since we don't have it right now it's okay we don't need to show that okay we basically need this model to show up when the user tries to access a feature that require re Ires a subscription we basically need to use some logic there to prevent the user from adding a folder if they don't have a Pro Plan so let's go into the sidebar shrink this go into components and then folders drop down right in here and right here guys we have I think we already have it y right here so we need to check if the length of the folder is greater than or equal to three and there's no subscription so if this is the case then we're going to go ahead and open that modal on the screen set open to True okay this is going to come from that mod of the provider that we just created and then we're just going to return so we're going to stop from here so let's go up top and let's import that so const open and set open use subscription model like this and that gives us access to these two things now it should work there we go awesome so after this you want to have the description so we're going to say dialogue description from UI dialogue like this and this is going to have to access it you need to upgrade to a Pro Plan and after this description we need to get access to the products okay and these products we're going to pass down eventually for now we're not going to focus on that we're just going to return um like a one like a single product okay so what we're going to do here is just say div and then give it the following class names Flex justify center items Center and then we just going to create a react. fragment and the reason why we're doing this here is when we Loop across we need to provide a key key and inside this react fragments we're going to use uh the Bold tag here like this and let's give it a class name and say text -3 XL and this is going to basically have the pricing and things like that okay text- muted foreground like this oh sorry text foreground guys not muted and after that inside this we're going to create a helper function and that helper function is going to basically basically convert our pricing in into some sort of a format okay so you want to go into your utils or whatever we have a utils here right and you can just say export con format price like this is equal to a function that takes in the price and um this price is going to be of a special type okay this price comes from the types that we created initially so from the super base types if you remember const price string equal to new inl like this do number format and invoke this and the first one's actually the type so we're going to say en do- US like this and pass in the object for uh the options okay and here we're going to say style is going to be currency and then the currency is going to be price. currency or undefined and then finally the minimum fraction digits is going to be zero format this to price do unit so question mark unit amount or zero um we're also just going to say like this and let's return the price string so that way we can use this so let's go in here now into our subscription model so we're going to say format the price let's import that as well 12.99 like this dollar sign we'll come back to this all right I just wanted to build that out then we can say small we can also put a slash like this and say uh month cuz this is this is going to be the interval create a button like this make sure you import it from UI buttons and say disabled is equal to is loading const is loading and set is loading equal to use State like this and false okay now let's go to the bottom here just say is loading if it's true then we're going to return something else we're going to return something so if this is the case return the loader that we created or just return a string and call it upgrade with this one now that we have this set up um we can go ahead and just test this out awesome there you go and it shows upgrade to this Pro Plan and you can of course click the button and then it does something okay but um one thing I don't want this to be centered all right that is so much better so basically if there was no elements this one if there was nothing in here we want to just return a string so hide that and if I go ahead and just hit the plus all right it just says no products available so now you want to go back into to your settings form component and we're basically going to check for the subscription here and we also want to render some buttons where they can um change your subscription status and things like that so let's go ahead and use a link which comes from next link just like this and um this is going to have an hre and this href we're just going to set to like this okay and we're going to say Target equal uncore blank okay and after that we want some class names so we're going to say text- muted - foreground then we need Flex Flex row items Center so we're going to say view plans and we're going to say external link icon or external link from Lucid react you can see we have the view plan so the user clicks this button it takes them to the main page and then you can just show that here let's also give this a size of 16 and then after this subscription oh sorry after this link we want to say subscription. status okay and if it's equal to active we're going to return a div and inside this div we're going to return a button and this button is going to say manage subscription and uh we're going to provide the following props for this button the type is going to be button the size is going to be small vary in secondary disabled is going to be loading portal and the class name is going to be text small and on click is redirect customer portal so when the user clicks on manage subscriptions we're going to send them to this portal and the portal takes a while to spin up guys and we're going to use stripe to make all this work for now let's hide this cuz we haven't come to the sub the payment section yet right so we want to do that and here instead of this we're going to return a div U same thing another button here but it says start plan this star plan is going to have type button size small variant secondary and this class name is going to be set set to this also I'm going to just say work in progress right here so we can capture that when we make a quick search to make sure we've done everything and this on click is basically going to set that um that state remember that we just created right the provider it's going to set that to true so it's going to show the plan on the screen so let's go all the way up top right here we're going to say const open and set open equal to use subscription model there you go so you go here there's no plan so if you click Start Plan it's going to show this and then you can go ahead and upgrade um to the plan okay that's what we wanted to do here so great job so far let's go ahead and um check where else do we need this and guys you can use this everywhere you want okay you can literally set restrictions like right now we have a restriction for the folder you can set restrictions for other things as well okay so one thing I'm going to do right now for you is to show how we can prevent the user from uploading a custom logo right here the works space logo so I'm just going to look for uh workspace logo like this right here and this input needs to be disabled okay say uploading logo or the subscription. status is not equal to active so if it's not equal to active it's going to show this message here so let me show you it's I mean it's going to basically set it to you know you cannot update it because you don't have that uh option and what is the error here let me see I did this one more time sorry guys active like this after that we have to put the subscription stuff in here right so let's say subscription. status if this is not equal to active we want to return the following a small tag with the following class name which is text- muted D foreground inside this we're going to just say uh to customize your workspace you need to upgrade to a Pro Plan first and there you go it just shows the message to the user so they can know oh I need to upgrade to this and here's a challenge do the same thing for the dashboard setup page so in here if you go to your dashboard setup which is right in here go ahead and do the same thing in this dashboard setup for that component okay let's go back in here we can remove this flag now because we're done with that I think now is a good time to go ahead and set up payments for our application so we're going to do a bunch of stuff so just be with me um it's going to be a little bit of code so before you get started make sure you have a stripe account so go ahead log in create a stripe account and then come back once you're done okay I went ahead and logged into the stripe account and make sure you have your test mode set to this okay it should be on and you should see this test data right here okay so I already went ahead and did all this stuff and that's why I have all this but don't worry um you know we're going to do it from scratch right now so that way it's easier for you to follow what you need is you need the stripe publishable key you need the stripe secret key and a web hook key okay so let's go ahead and get that set up go to the search bar here and look up API Keys okay it's like this I don't know why the hell they have this kind of dashboard it's really bad but um yeah basically you want to go into developers and get this API keys from here you're going to see this publishable key right here okay go ahead and copy that so click on that key copy it and paste it in here and then the next thing is the secret key so go ahead and reveal the secret key and then copy the secret key here too and paste it in here and then we need to go ahead and get the web hook secret so to get the web hook we have to get it from here but before that I want to just let you know this is how we do it in the local environment because we're testing but in production we're just going to add the end points and then change that but for local tests you want to go ahead and click on this test in local environment and it's going to spin this up for you okay it's going to show this for you and you need to go and download the CLI and log in so this is something that you need to do and if you haven't um if you haven't done this it's actually pretty simple open this right here guys open this download CLI and it's going to show you exactly how to do it so if you have home brew you can go ahead and do Brew install stripe CLI and stuff like this or you know if you're a Mac OS you can also run these commands but this this is the easiest way okay make sure you have home brew installed and then you can just do Brew install and get this in here okay and then after you have done downloading the CLI okay please keep in mind you need the CLI you need it because that's the only way we can run this web hook locally to get that key you will need to log into stripe and then you'll have to do stripe listen forward to a web hook that we haven't created yet which we need to create okay but I just wanted to give you guys a heads up because if you're wondering where the hell do I get this web hook key from we will be getting it from here okay but before that we need to set up stripe on our end to generate those keys for us and also keep the endpoint ready and things like that okay awesome so let's jump straight right into it so first thing we're going to do is head into your Libs folder and you want to create a folder called stripe and inside this stripe you're going to create three files okay admin tasks. typescript index. typescript finally the stripe client. typescript open your terminal and just type in npmi stripe first let's go to our index. typescript file file we want to import Stripe from stripe and then we want to export const stripe equal to new stripe and we need to pass in our stripe secret key okay so let me make sure I copied this I don't want to make any errors in this spelling so secret key copy this guys please don't make any mistakes here um like I did in the past because this is going to be a pain to actually debug okay so make sure you copy and paste the string no harm okay even if it's wrong but there it's the same thing it's fine so we're going to just do this in here like this put this and then we're going to put an empty string and then we're going to pass in an object with some properties so API version 2023 where is that 2023 10 16 so whatever it gives you okay um I actually had it at 08 but we're just going to do this app info this is basically the setup so we're going to say name web prodigies Cypress and then we want to have the version set to 0.1.0 and the next thing we need is another package to make this work so it's called npmi stripe slst stripe DJs go ahead and hit enter now we can go into our uh into our stripe client file which is right here and we can we can import these packages that we need which is load stripe and Stripe from here which comes from add stripe.js that we're going to say stripe promise promise is going to be a type of Promise which has stripe or null okay and then we're going to export const get stripe equal to a function like this and in here we're going to say if no stripe promise this is not promised this is promise so if no stripe promise like this then we're going to return uh then we're going to do stripe promises equal to load stripe invoke it and we have to pass in our publishable key okay so I'm going to copy and paste it in here because I don't want any errors so let me go into myv file I'm going to copy that and I'm just going to paste it in here okay awesome and after this make sure to inside here inside the function make sure to return the stripe promise and then next thing is go into your admin tasks and what we're we're going to do in here guys is we're basically going to uh set up the tasks that our admin would create such as creating prices creating uh products so let's go up top right here we want to say export const we're going to say upsert product record it's equal to async which is a function and this is going to get the product which is stripe comes from stripe itself okay so stripe. product like this and in here we want to say const product data is of type product okay this product comes from our superbase types to set this equal to an object with ID which is going to be product. ID okay it's going to have active product. active oops this is not comma this is dot we need the name which is going to be product. name description which is going to be product. description um null like this okay and then we want to say image which is going to be product. images um if this exists at zero if not null and then we're going to say metadata which is going to be product. metadata and after this part we're going to do a TR catch and in this TR catch we're going to say await DB do insert into the products okay product from migration schema okay insert into this values and then we're going to say product data this this new thing that we just created right here so insert the product data and then on conflict so if there's a conflict we want to update it okay and we're going to pass in this object and we're going to say Target is the product. ID okay and then we need to set something so set product data like this uh it okay it's products dot so this products if there's an error we want to throw the new error just like this so we're just going to do this here and then we're going to console.log product inserted okay or updated product. ID just like this okay the next one we're going to need is the price this one is going to be called upsert price record which is going to be equal to async function and this is going to get the price and if you're wondering where are we going to call this guys this is basically um this will come from our web hook okay so our web Hook is going to fire when we when we create a product inside stripe and then stripe and the database are going to be synced so this price is actually going to come from stripe. Price like this and inside here we want to create the price data okay so to save you time I'm just going to go go go ahead and copy this do it with me guys okay do it with me um I'm just going to say price data equal to this so this type here is price and this comes from our superbase types okay so we have to have the ID which is price ID product ID which is type of price. product string okay if it's equal to string then we're going to return that product if not we're just going to return null okay active is going to be set to price. active currency price. currency description price nickname okay and if not null and then type is price. type unit amount is price. unit amount make sure you use these underscores because this price that comes in here from is from the web hook okay so it's going to be slightly different unit amount is price. unit amount null interval is price. reoccurring interval and then null and then interval count is priced. reoccurring interval count if not null trial period days is priced. reoccurring trial period days if not null and the metadata is going to be price. metadata and in here we're going to say await db. insert like this uh into prices so I'm going to bring that from migration schema we want the values to be the price data that we just created and on conflict do update okay we're going to update it if there's some error all right let's do this and we're going to set the target to to be the prices. ID and um we also need what to set so set price data if there was an error here we're just going to throw a new error saying you know could not insert or update the price and you can just put the uh the error like this so we can just say error okay after this you can just put a confirm confirmation message saying the price was inserted started successfully great and now the next one is to create or retrieve a customer okay so let say export const create or retrieve customer like this equal to another function and this is going to be an async function right here and this is going to take in the following so it's going to get the email um so this is going to be an object sorry the email we're also going to get uu ID like this uu ID and of course we need to set this so email and email is going to be string and uyu ID is going to be string as well in here we're going to say try catch and we're going to say const response equal to await dbquery do uh customers. find first so we're going to find if the user already exists as a customer we're going to say where and this is going to be a call back function so let's just say this this will give us the customer and an object here called equal equal C do ID and The UU ID that was passed in okay then we're going to check if there's no response okay then we're going to throw new error then we're going to return response. stripe customer idid and after this in here we're going to say const customer uh data is going to be an object with metadata set to an object with a superbase uuu ID so I'm just going to copy this uu ID like this and I'm going to say it's going to be a string email is optional which is going to be a string as well and this is going to be equal to an object with metadata set to an object with superbase uu ID equal to The UU ID that was passed in if email exists then customer um where do we create that customer data so this one customer data. email is going to be equal to email and then we're we going to create another TR catch in here and we're going to say const customer equal to8 stripe. customer customers so let's go ahead and import this stripe and this stripe actually comes from our index file let's just go up here and let's import it so we got to say um like this okay import Stripe from index so this is going to be customers. create and we're going to create the customer data okay create this customer data and we're going to say um after this we're going to say await db. insert into customers from migration schema values like this ID is going to be uu ID and the stripe customer ID is going to be the customer. ID and then we're going to say console.log a new customer created right here let's just say new customer created and we're just going to put this message in here with their specific uu ID and we're going to return the customer. ID if some error happened we can just say stripe error and then we can just throw this error finally we have to copy billing details to customer that's the final one so let's let's say export const this is equal to a function so copy billing details to customer and this is going to be an async function and it's going to give us um uu ID which is going to be a string and the payment uh the payment method okay so payment method which is going to be stripe. payment method okay just like this and then const customer equal to payment method do customer as string like this and then we're going to say const name photo and the oh sorry phone and the address is equal to payment method. billing details no name or or no phone or oops or there's no address return if not we're going to do await stripe. customers. update um the customer like this and we're going to say name comma phone comma address and then we're going to do a quick try catch like this and in here we're going to say await db. update inv this and we're going to say uh users where is that yep users. set okay we're going to set the billing address to be everything inside address and the payment method is going to be everything inside payment method payment method at so this this thing like this let me write that one more time so payment method at so this is an object payment method type okay so payment method. type after this we're going to say dot where equal to import this from drizzle omm and you want to say users. ID equal to uyu ID and then we can throw an error here like this saying could not copy the customer billing details and then let's go down here and now we want to say export con manage subscription status change which is equal to a function and this is an async function and this is going to give us the following um parameters which is subscription ID which is a string customer ID which is a string and the create action in here too we're going to say try catch and we're going to say cons customer data equal to await db. query. customers. find first invoke this and we want to say where and this is going to give us the customer and an object like this let's destructure it it's called equal and we're going to say equal c. strip customer ID and customer ID that we got in and then we're going to say if there is no customer data we're just going to throw a new error cannot find the customer okay and after this we're going to say const ID so const ID like this is um let's rename this to UU ID is equal to customer data we're just destructuring it and then we're we're going to say con subscription not subscriptions subscription is equal to await stripe. subscriptions from here dot um retrieve invoke this and pass in our subscription ID from the parameter and an option object here which is going to have expand oops sorry expand set to an array here with um with default payment method as the first prop okay the first value and then this is going to be a little big here it's basically the subscription type so we're going to create a subscription right so we're going to say subscription data equal to um sorry this is going to be of type subscription from superbase types ID set to subscription. ID um user ID is going to be uu ID like this metadata is going to be subscription. metadata status is going to be subscription. status this is going to have an error here and we need to actually do typescript ignore so um there's something wrong with this here so just do this just do this right here you want to say the price ID is going to be the subscriptions do items. data at z. price ID sorry do ID like this and then we also need the quantity the quantity is going to be subscriptions. quantity okay so something is wrong here um I think this is actually just a typescript problem so um yeah you can just go ahead and just say subscription. Quantity guys this will work but just do H yeah just just do at uh typescript ignore okay I think it's going to work um in here we also need to say cancel at period end is going to be subscription. cancel at period end like this and then we have our cancel at which is going to be subscription. cancel at um cancel at like this and what is this problem here okay so it looks like this could be null so what we're going to do is we're going to check if this exists okay so this 2day time is actually a custom function that we're going to create and that's going to come from another folder uh called utils another file called utils okay so go to your utils right here export const to date time equal to a function with the seconds which is going to be a number and this is going to say VAR t equal new date and we want to pass in um some date in here so I'm just going to copy the string okay you can just past past it so just look 1 97 0 01 and we're going to say 0 1 t0 0 here then 30. z00 Z okay and then we're going to say t. set seconds to be seconds the thing that we get in like this and then return the T okay so now we can come in here so I'm going to say two day time from U TOS like that let's go to the bottom where is that right here okay cool so that's the helper that we need needed so we just created that which is going to take in the subscription. cancel at time it's going to return something two dates time let's go in here guys sorry about this made a quick mistake here and we're going to set 2 ISO string and invoke that like this or null like this so I'm seeing another error here the first error is at address so what's wrong here oh you cannot pass in this okay so we'll remove that and for this error actually let's not just remove it like that let's actually take this because I want to see the message it's going to be very hard to debug these things and we're going to say dollar and just say error like this so we can at least see it okay so I'm seeing something in here which is address is not assignable to type address pram undefined address is not assignable string or null is not assignable to string or undefined just give me one second I'm going to fix this okay so guys I'm sure if you you look here this address type is of type stripe address or null and here it's saying that string and null can is not assignable to type string or undefined so this seems to be some sort of a typescript thing that is not under our control cuz clearly we're checking here right so I'm just going to say typescript ignore okay for now I'm confident that that's going to work um that does not make any sense but whatever okay so cancel let's continue so right here we did this cancel at null and then we have to also do cancelled at null so cancelled at is going to be um the following it's the same thing okay subscriptions. canell at to dat time a subscription. canell at2 ISO string and you want to put null in here and then current period starts to date time the subscription dot so I think we have a current period start okay this one and. 2 ISO string just invoke this just like this the current period current period and date which is to date time invoke this subscription. current period end date. 2 ISO string and invoke it just like this just a couple more properties end it at so ended at which is going to be a subscription. ended at if that exist then we're going to do to dat time invoke it and say subscription. ended at like this do 2 ISO string and invoke that so instead of sending an empty string we have to send a null and then the trial start two more values so only the the second last one the trial start is going to be subscription. trial uncore start like this if this exists then we're going to say to date time subscription dot. trial start like this do2 ISO string and you want to invoke that if not you want to return null finally the trial end is going to be subscription. trial end if this exist we're going to say to date time invoke that and pass in subscription. trial end if not we're just going to return something else which is uh null okay and oh we need to say to ISO string and invoke that as well after um this right here hit enter and you want to say await DB do insert into subscriptions uh subscriptions from the migration schema do values you want to pass in your uh new subscription so subscription data and you want to also set the conflict update okay so on conflict update the target is going to be set to subscriptions. ID set is going to be set to our new subscription data so we'll just set that so subscription data and then you can just console log a message saying hey this is successful inserted it for this user and then we want to see if create action and subscription. default payment method oh also The UU ID then we're going to await copy the bilding details okay we're going to copy this billing detail so we're going to say copy billing details to customer uu ID and then subscriptions um subscription. default payment method as stripe. payment method um just like this so so go into your U tools file we're going to create a function here called export const get URL equal to something like this and we're going to say let URL L equal to process um. EnV do um next public site URL or we're going to return this um next public Planet scale or yeah maybe Planet scale URL okay and then um if not we're just going to set our Local Host so in here oops go right here and just return our Local Host uh 3,000 just like this and then you want to make sure include the https so you're going to say URL equal to url. includes HTTP okay and if so URL if not https dollar sign URL just like this and then URL is equal to url. character at you want to set url. length to uh minus one and then this is going to be equal to a backslash if this exist um then we're going to say um URL if not we're going to return a new string and say dollar sign URL like this and put a backs slash at the end okay awesome and then we want to return the URL it's just a helper that we're going to need and then we're going to need the post data URL it's just a custom post data to kind of create this request and response so we're going to say const post data equal to async inside this you want to say URL and the data and this is going to have the following types string and the data is going to be an object the price set to type of price from yeah superbase types and after this just say console.log posting the URL so we know what's happening and then we're going to say const res which is our type response equal to await fetch URL not data actually we have to pass in an object with the method so this method is going to be post method right here and and then we're going to have the headers set to new headers like this invoke it and say content type application Json the credentials is going to be set to same origin and then the body is going to be set to json.stringify data if not res. okay console.log like you know error in the post data something like that and then going to throw okay and say res. status text finally return our res. Json great job that was a lot of code um there is we're almost done guys we're almost done so you want to go into your API folder this is basically our checkout sessions our portal links and all that kind of stuff and our web Hook is also going to be in here create a folder and say create checkout Das session inside that create a route. typescript and in here we're going to basically export an async function called call Post and in here we're going to have the request like this and in here we're going to say const price uh we're getting this from the request. Json by the way so we're just we're just destructuring and this is equal to await request. Json try catch const superbase equal to create route Handler client import cookies from next SL headers and now pass in the cookies also want to check get the user so we're going to say const data user equal to await super base. o.get user invoke this const customer equal await create or retrieve customer okay and we're going to pass in the email which is going to be user. email and the uuid which is going to be user. ID we'll just pass in these empty strings right here okay and then you want to say const session equal await stripe this stripe actually comes in from our Libs folder guys so stripe lib stripe okay that folder do checkout do sessions. create so we're creating a session here and uh we're going to set the payment method types to be card like this this is going to this might give us a typescript error if not we're good okay cool and then we want to set billing address collections to be required customer like this all right guys this is spelled customer and then we need the line items which is going to be an array with an object like this and this object is going to have price which is price. ID and the quantity okay and then after this mode is going to be subscription allow promotion codes you can allow this too no problem subscription data is going to be an object with trial from from plan trial okay so yeah I I don't know it's not there on the types so just do trial from plan is going to be true and then uh we also have to pass in the metadata so we'll say metadata is going to be just metadata like this okay um all right so there you go it's showing us that typescript error so I'm just going to do typescript ignore after this we need to say success URL is going to be get URL pass in slash dashboard can URL is going to be the same awesome you can do more advanced stuff like sending them back to the exact URL and all that kind of stuff no problem but I'm going to return the next response import this from next server. Json and we're going to set the session ID it's going to be sessions so I'm going to where's the did I say sessions here okay I did say session here okay so session. ID guys just like this error here this is going to be any and I'm just going to return this um internal error with a status of 500 the status is important okay now we have created our checkout session so let's go ahead and create the other stuff so I'm going to say create Das portal dlink a route. typescript inside this as well so I'm just going to say route. typescript so we're going to export async just invoke it like this and then we're going to say TR catch and inside this we're going to say con super base equal to create route Handler client and pass in cookies import cookies from next SL headers and after this we want to say const data and user equal to await super base. o.get user check if there's no user there's no user we want to throw a new error and then we want to say const customer equal to await create or retrieve the customer with the email set to user. email or we're going to just return a string like this and then it also needs the uu ID which is going to be user. ID or an empty string like this okay if there is no customer throw a new error and we're going to say could not find this customer and then after this we're going to say const we're going to destructure URL from await stripe and this stripe guys comes from the libs folder okay building portal do sessions. create and then we're going to say custo customer return URL is going to be that same dashboard thing that we created okay so I'm going to just going to pass that in here import this from our Libs and let me go back and actually make sure I didn't import the wrong get URL yep there you go I knew it I made that mistake so let me go in here and import this from Libs uols and now let's go back to our portal and we need to also send a return so uh next response like this Json invoke this and pass in url and after this finally in the end we're also going to just print some error the same thing as we did the last time guys print some error if an error occurred and then return the next response with the internal error and don't forget to put this 500 the status 500 in here I think there's one final one the web hook that we need to create and this one's going to be relatively simple not too bad let's shrink this and inside the API folder create web H and inside that route. typescript first say const relevant event so this is basically from the stripe gu so just copy paste this okay you can go to the GitHub and just copy paste just put that in there we're going to say export async function post going to say request is going to be next request from next server and in here we're going to say const body equal await request. text and then we're going to create a signature so headers actually comes from so from the next headers guys sorry about that and we're going to get the stripe signature so get stripe signature and next we need to fetch the stripe web hook secret we're going to say const web hook secret is equal to process. environment. stripe webhook secret okay so this one process uh web hook secret live make sure you copy and paste this stuff if not we're going to say stripe web hook secret so the one we have right in there so when we're live we're just going to change that web hook secret as well and then we're going to say let event which is of type stripe. event and this stripe comes in from stripe itself so stripe. event and then we're going to say try catch so let me just use this snippet here yep try catch if there's no signature or does no web hook secret then just go ahead and return if not we're going to set the event equal to stripe this stripe comes from lib stripe again so lib stripe. web hook. construct event not async this one body and then we're going to pass in the signature and then we're going to pass in the web hook secret oh no web hook secret cool guys and then later we can just show another error but this error message is 400 and now we're going to check which specific event was requested or received and then we're going to invoke all those admin functions that we created so after this try if relevant events. has invoke this and say event. type then we're going to do try catch and in here we're going to do switch invoke this and say event. type case product created and product updated so you can copy it from top and paste okay so for these two events we're going to await upsert product record and say event do data doob as stripe. product and then we're just going to break out of this and then after that we have the price created and updated we're going to do await upsert price record passing the event. data and doob as stripe. price and then for case customer. subscription. created updated and deleted for these three types we're going to do const subscription equal event. dat .ob as stripe. subscription await manage subscription status change and we're going to pass in the subscription. ID the subscription. customer as string event. type equal to the customer subscription created and then finally let's just go ahead and break so case checkout session completed cons checkout session is equal to event. dat. object as stripe checkout session and then we want to say if checkout session oops not this one if checkout session so this um this one. mode is equal to subscription okay then we're going to say con subscription ID equal to this checkout session. subscription and then we're going to say await manage subscription status and we're just going to pass in the same data but here it's going to be true so subscription ID as string checkout session. customer as string and then true let's just go ahead and break and then default we need to throw a new error cuz it's some weird um event and we're going to say unhandled relevant event or something okay when the error happens print console.log the error and we're going to say we're going to return new next response web hook error and we're going to say web hook Handler failed and set the status here to 400 don't forget about this guys we're going to return next response Json and we're going to pass and received as true another object after this and this object is going to have the status of 200 like this oh okay sorry guys we have to say default here I don't know why that disappeared I accidentally might have deleted it so default throw new error unhandled relevant error so now I'm just going to go ahead and log in here so I'm going to say stripe log in like this all right guys so go ahead and just do that so click on this link and paste this if gives it to you okay so I just did that off screen click that and just hit allow that's it and then it's going to show this this message in here now you can see it says logged in as dev. loal so now we need to listen to this web hook don't forget you need to run the web hook at all times on local environment because if you don't do this then your database is not going to be in sync so copy this open another terminal put stripe listen forward but not Local Host um for 4242 it's going to be 3000 SL apiweb hook and then go ahead and hit enter perfect so it spit out this web hook secret so now copy this web hook and go into your environment file and paste that uh link that you just got this one right here don't put any spaces or anything like that just paste just that web hook secret it just says here too right and it's also saying listening for events so copy this if everything works worked out perfectly this should do the job so we'll create another terminal copy that and just hit enter now go back to the other one okay so it says some error happened let me go ahead and take a look at it what we did is we didn't even run npm runev so that was the issue okay so go ahead and run npm runev and then now when you set that trigger paste this in here and you hit enter and then you go ahead and look at the API responses you will see 200 everywhere so this means our web hook is running so go ahead and hit done here and now we need a product so go up here and look for product catalog but uh we had some sort of error let's see what's the issue here so it says product okay we created this price here and we passed in the price this did not even invoke it didn't throw any error so let's go ahead and um archive this product apparently you cannot delete a product which is which is crazy to me but okay let's just go ahead and delete this and let's add a new product in here so it's saying make sure that says test data up here okay so we're going to say um Pro plans standard pricing we're going to just set it to 12.99 sorry not 12,000 that would be insane $199 it's going to be reoccurring okay and we're going to set it to monthly and save this product like this product inserted price also has been inserted undefined values are not all love okay there seems to be some error here but it's not actually blocking the application itself let's refresh okay product was created and active is set to True right here like this so This Pro Plan is active and our prices should also have it because we did not see any error right there we go so I'm not sure where this error is actually coming from but hey our pric is created and the product is created now that we have our products set anytime you you want to update your products for somebody else right A client they can just head over to their stripe account and they can just update the product here and everything is going to update accordingly now we can go back to our application and we can start to show some data in there so right here go into your main folder and you want to go into your workspace layout. JS okay sorry um not this workspace actually wherever we put the sub subcription model so yeah right here so we're going to say products and this is going to be equal to the products that we're going to find in just a second so we need to create an action for this so go into your Libs folder go into superbase queries and in here just say export const get active products with price and this is going to be equal to async we're going to have a TR catch in here which is going to say const res equal to await db. query. products doind many where passing a call back like this I mean a function and we're going to get the product so I'm just going to say Pro or something like this and equal where the product. active is true so only those products that's the only thing that we want and now you're going to notice that our width is not going to work in here and the reason is because we haven't set relationships in our our data so you need to do one to many and many to one relationships in order to use these um with queries and things like this okay so I'm going to show you an example of how you can set that up it's actually very easy you can do it for the rest if you want to it's just a lot of work we just want to focus on the core of the application go into your schema okay superbase schemas scroll all the way to the bottom and we want to say export con products relations is equal to relations which comes from drizzle omm passing the relations first for the products products from migration schema this is going to have a many relationship we're going to return an object and this object is going to have prices prices set to that many for the prices and then we want to set the price relation equal to relations and you want to pass in the prices and we're going to get one product is one products like this and we're going to pass in an object and we have to pass pass in those fields an array of the prices. product ID it references something so we're going to say reference products. ID if you want the relations for everything will definitely help you in the Discord but I just want to show you how to use these queries properly with Drizzle okay we also have to push um our changes npm run generate npm run Dev npm run pull we need to update our schema so I'm just going to go ahead and update that subscriptions okay so something is wrong here guys let me see what's the issue all right guys so I found the error and the error was because we were since we're using the schemas from our migration schema we have to paste the relations in there now when you go into your queries you will also get the type intelligence and also we were we were actually editing this find user in the beginning but that's that doesn't really matter but now if you say width and you say prices you will see all the the type Intellis so that means relationships uh have been set up return if this is true um and we're going to return the data set to response and the error set to null if there's an error we're just going to print that error and we're going to return this right here data with an empty array uh the error itself now let's go into our layout component right here we're going to fetch for those products okay so we're going to say const data products error equal to await get active products with price this is supposed to be an async function just like this and error here um data what seems to be the problem uh if there's yeah so here we want to return data at an empty array and error um set to null if error we just want to throw a new error like this okay and now inside this uh model we're going to pass in the products and let's go into this model because now it does not have have access to these products so in here we're going to say products and here we're also going to say products and this products are going to be product with price and it's going to be an array and now in this subscription Mo model we're going to pass um pass down these products like this which is equal to products like this and now let's go back into our model interface subscription modal props is going to have products set to product with price I also have made an error here but that's okay set to an array react. FC like this and we want to pass in a subscription modal props like this and let's go ahead and extract the products okay so now that we have the products now we can Loop over um that product and we can return this new div in here or no product wrap this whole div right here so you can just remove it for now and you're going to say products. length so if this is true then you're going to do something if not not you're going to do something else and in this products. length in here we're going to check products do map so for each of them like this and for this we're going to return a div this div is basically what we're going to replace with what we just cut and now we're showing this here but this react fragment is going to have the prices in here okay so let's remove this uh and first let's Al to pass in the key so key equal to product. ID let's remove this react fragment and we need to say product. prices. map invoke it and get the price and we're just going to paste this react fragment in here this right here is going to be that function that we created format price invoke it pass in the price and put a back slash after this with a space this is going to be the interval so price. interval so let's go up here in our layout component all right guys I took a look at it and it it was basically because we had maxed out our connection ction slots and that's why we couldn't so that's why the data wasn't coming back so everything is correct okay so you don't have to worry about anything basically it's if you go here and you click see we don't have any prices but if we click it's showing the uh the number and the month as well so finally we need to have an on click in here so I'm going to say onclick is equal to and this is basically going to create those portals that we just built out so let's say onclick continue like this and this is a call back function so I'm going to go up top here and I'm going to create this function up here const this function equal to an arrow function and this is going to be an async function inside this function we're going to get the price which is set to price from superbase types we're going to use a TR catch and we're going to check uh we're going to set is loading to True guys if there is no user which we need to get so we're going to go in here and we're going to say const user user equal to uh use superbase user and this is we're extracting the values from here so user like this so if there's no user we're just going to use a toast okay so we can const toast equal use toast like this so if there's no user oh we don't need this again we can just show this message and then we can also set the is loading to false and we can return out of this real quick if the subscription exist and going to say Hey you already subscribed to the plan so you don't need to do that and set the is loading to false well if all of this is good then we're going to create our session okay so session ID equal to await post data invoke this and pass in the URL and this URL is going to be SL API SLC create D checkout Das session like this okay and it needs another um property which which is the data which is going to be the price when we click here we're going to pass in that specific price into this uh onclick Handler let's go back up and here where we say data. price after this hit enter console.log getting checkout for stripe and then const stripe equal await get stripe which is from our stripe client and then we're going to say strip. redirect to checkout and we're going to pass in that session ID if there was some error that took place we'll just go ahead and show another toast here and then finally set is loading to falo after everything we also want to set it to false great so if I click here now okay this user clearly is on a free plan right and we can tell from this if you click this right folders it's going to show this model and now if I hit upgrade it's going to load something and oops something went wrong so let's go ahead and see what went wrong okay okay so right here when I post the data right here I basically said um check out sessions okay so remove this to session and the reason is because our route is set up like that create checkout session right there let's see if this solves a problem and then we can go to this folder here and then hit upgrade okay and now it takes us to the checkout page guys how awesome is this okay so here it's basically just checking if the user is real and it's sending them an actual email confirmation to a mobile number right here okay so um you can check out as guest which is better go ahead and enter some credit card information right here um just put in 424242 all right so I just went ahead and put in some fake information right here so you want to say 42 42 42 and um this can be any number that is valid the date and this should just be 4242 it's fine it can be anything okay and here I just put in some weird address um some North University from Illinois or something and go ahead and hit subscribe so let's see if everything looks good and if everything does it's going to send us back to the dashboard awesome so check out confirmation and uh there we go guys great stuff and now it says we are on a Pro Plan and now you can go ahead and create as many folders as you like 1 2 3 4 5 amazing stuff right go ahead and go to your settings page so settings settings form. TSX now when we're adding a works when we're adding collaborators we can actually limit the number of collaborators right in here okay so I'm just going to uncomment this and I'll delete this subscription stuff and we're going to check if it's not equal to active and the collaborators do length is greater than and equal to two so this means the user is on a free plan and now let's go ahead and build that functionality to basically manage the portal so let's go ahead and turn this off and turn this um off as well and let's remove this work in progress let's scroll up top and we can create that function const equal to this something like this the loading portal is just going to be a state so just create a state to first set the loading uh for the portal to true in here we're going to say const we're going to destructure the URL and the error from await post data make this an async function come down here and import this post data and in here you want to pass in the URL that we need so SL API slre Das portal dlink so go back into this function guys and where you have data in here just put a question question mark okay cuz it's optional and then we're going to set window.location location. assign like this and we want to pass in that URL that we just received if there was an error we're just going to console log some error and finally set the loading portal to false now if we click on settings go to the bottom and you see this manage plan manage subscription if you click it it's disabled and awesome guys there you go it takes you to the cancellation page where the user can go ahead and cancel their plan or they can update you know update everything their payment information all that kind of stuff so everything is already set up for you how awesome is this all right guys so what you want to do is head over into your folders let's quickly just shrink this right here and we're going to go into source and to components create a folder called trash and inside that you want to say trash Das uh restore I guess. TSX okay and then we want to create another one called trash. TSX and let's just do ra fce trash this is basically the same custom dialog uh trigger component so quickly let's create the interface let's create the trash props this is going to be equal to Children which is going to be react. react node like this and in here we're going to say react. functional component and let's go ahead and pass the trash props in here okay trash props like this and let's um let's destructure the children from the props and U then all we need to do is return our new component here okay which is going to be the custom dialogue trigger and inside this we're going to say header is equal to trash like such and then the content is going to be equal to um yeah content is going to be equal to our trash restore component which we're just going to import in just a second so trash restore component just like this okay children is missing so go ahead and pass in the children in here like this and let's copy this trash restore go into our trash restore and say rafc and just paste that in right there and let's import this okay let's first create some state so we're going to say const um state dispatch okay because we need to bring back stuff and the workspace ID maybe folder ID we might need these things and let's make that equal to use app State like this and then we also going to need the folders and set folders equal to use State like this and then this is going to be of type app folder type and it's going to be an array of this or it's going to be an empty array and in here we're going to pass in this empty array and then we'll also need the file so we're going to say files and set files just like this equal to use State invoke this and pass in file um of an array or an empty array and in here let's go ahead and pass in this empty array so we're going to have a use effect and this use effect is going to fetch this data from our from our local state okay so what it's going to do is we'll just have a um we'll have state in here for now and we're going to basically say const State folders equal to and we're going to find the workspaces where the workspace ID is equal to the workspace ID we're on and then we need the folders and we're going to filter for where the folders are only in the trash okay and then we also going to return this as or we're just going to return an array like this okay and then we're going to say set folders to be equal to State folders just like this great job and then you want to say let State file files which is of type file from superbase type and it's an array and it's equal to an empty array for now okay and then uh we can just say state. workspaces doind the workspace where the workspace doid is equal to workspace ID like this then get the folders from that and then we want to check folders. for each okay actually we don't need to do this cuz we want to get everything in here right so yeah we can't we don't even need this folder ID in that case I thought that's why we needed it um so in here what we're going to do is instead of this we're going to just do folder dot um files dot for each if the file is in the trash then we're going to say State files. push and we're going to pass in the file and at the bottom finally uh we want to also set the state files of sorry set files like this to our state files that we just have right in here we're going to remove this and return a section if folders. length then we're going to return something so we're just going to return a react fragment and inside the react fragments we're going to say H3 sorry H3 like this and give it the following actually no no need for anything in here we'll just say folders like this and let's create a link give it an href equal to SL dashboard SL dollar sign folder do. workpace ID which is actually going to be looped across so just remove this whole thing uh remove this whole link that we just created remove it and just say folders. map like this Loop over this and say folder and now you want to return that link okay and in this link you're just going to say um H equal to folder this folder. workspace ID and also pass in the key and the key is going to be equal to folder. ID like this okay and inside this guys oh let's see if we imported it from next link all right there we go and in here article aside like this and inside this you're going to have a file icon that comes from Lucid react and you're also going to have the folder title so folder. tile and for for this we're going to give it some class names to of course so we're going to say hover BG Das muted and then we're going to say rounded DMD p-2 Flex items D Center justify Das between and for this aside let's give it Flex items Center and a gap of two we're going to create another loop like this and we're going to say files. length and and then return a react fragment and just create an H3 and say files like this and then we're going to Loop over our files okay so let's say files. map let's get the file here and we're going to say the same thing guys exactly the same thing nothing different in here I'm just going to copy and paste we're just going to also provide the key prop which is file. ID like this and the same exact thing the only thing that's different is this icon changes to a file icon okay so just copy and paste it down here and now at the bottom if there is nothing if no files. length and no folders. length then we're going to return a div with a class name set to text- muted D foreground absolute top- 50% left- 50% and then transform and we have to do translate so negative translate X2 and then negative translate x uh negative Y and inside this we're just going to say no items in trash all right guys and now go into your native navigations which is inside your sidebar we're going to change this link to an Li so I'm just going to remove this one go ahead and open the trash like this import your trash component and move this list element into this component what seems to be the issue okay so the the trash component that I imported again came from Lucid react but we need to get trash up from you know our main our main component okay cool and let's pass this list item into this component and now we sort of have that wrapped around that okay so if we click on it there you go it says no items in trash just like what we'd expect if I go ahead and delete this folder go in here okay so it's not showing um let me see maybe we made some error somewhere let's go into trash re store okay so I made an error right here it's actually workspace doid is equal to the workspace ID and we need that workspace ID in here okay it's a dependency and I think everything else should work if I delete this go into trash boom there you go I see all my folders that were ever deleted in the past and we can of course bring them back so if I click on this it takes me to those specific links and uh you can definitely bring them back okay so what what happened here not sure okay so this has to bew workspace ID but slash dollar sign folder. folder ID folder. ID like this okay we made a small error here and what about this one let me see workspace folder and the file. ID this should be y this should be correct all right now let's go back to our test workspace right here and if we go into the trash we see a bunch of stuff right in here right right awesome and if we click on development it's going to take us to that specific folder okay so something is wrong all right guys it was because I had to refresh the page and that was just causing some problems but as you can see right now I can just go ahead and refresh everything and everything comes right back okay so if you click on trash again that folder is gone and you can also see the files uh let me go ahead and try to delete delete this folder so you see folders in the trash and there you go you see the folders right here and um you can bring this back by clicking on it or you can click on this too it's going to work perfectly fine and now you can restore it just like that so this is going to be folder icon like this from Lucid react and hopefully that looks slightly better and now if we go into the trash there it shows the folder icon okay you can click on files as well and you can also restore the file so restore this file boom there you go shows up right there and you can change this something like restored file let's so don't forget to you know look into the Discord and get all the help you need you don't have to struggle alone okay we're going to help you you have to do the challenges okay so if you go to the start of the file in the layout page right here I'm going to put all the challenges that you're supposed to accomplish okay and whoever gets it first put it in the Discord and let us know you know how you got it and uh just let us know who you are and we' love to get to speak to you hopefully we can build applications together all right guys so the first thing we want to change is actually this so and go back to your utils file this was actually set to Planet scale so go ahead and change this to railway I was just reading too much on planet scale and I ended up writing that so yeah just change it to railway here and the reason why we're using Railway and not versel is because socket.io will not work on versel versel is serverless and that's why we need to use Railway to deploy our application go ahead and open Railway and go ahead and log in right here with your GitHub click on this icon right here which is new project and deploy from GitHub repository okay so make sure you're logged in with GitHub and I'm going to go into GitHub just going to hit new repository like this and I'm just going to call this web prodigies Das Cypress and just hit create repository and it's going to give me some instructions copy this first line here and paste it in here and hit enter copy the main branch the second line paste this one and hit enter finally the push command and just just go ahead and push that so we'll do get add get commit and I'm going to say in it and then I'm just going to say get push okay there we go so now it went ahead and pushed everything and you should see Zero changes in here so if we come to GitHub and refresh this you should now see your new repository push to GitHub go back to railway and refresh the page so you want to click on deploy from GitHub app then click on configure and then just go ahead and do this setup all right awesome now it'll just redirect you back to this page click on get deploy with GitHub and now you can see your new repository click on the new one that we just created add some variables so just click on this and click on this raw editor so this will show up and now let's go into our EnV file so right here let's select everything and just paste it in here okay I see that we already are using a next public site URL so let me see where else are we using this okay so we're okay we're using it in socket provider and we're also using it in the email redirect to link which is good and we also have it in the util so you know what I'm thinking we don't even need this we can just update our next public site URL or we can just use Local Host right so I'm going to go ahead and remove this so let me see if I use this anywhere else okay so this is the only place so I'll remove that and I will look for the public site URL if there is nothing I will just use Local Host uh just like this and then let's go ahead and hit update variables all right guys I quickly wanted to just update I had to use a different account so if you have a new GitHub account Railway might actually block you from making deployments so yeah that's why I had to use a different account after you put the variables go to deployment and you see I've created two deployments here all right so I would actually suggest you do npm run build let's just take a look at this and see what it pushes out that way we can just catch some errors before we push okay um because I think there is a build build error so let's just take a look at what comes out I see one error here which is missing key prop so you can hold command and click on that and that's going to take you to where you have to put that key and in here where we said react. fragment go ahead and just put key equal price. ID get add get commit use key prop and then get push just like this that's going to go ahead and push to our main uh Branch all right guys so I saw a bunch of errors in the console I just want to show you and I did find some answers on this thread right here so basically I got this error saying Dynamic server usage page couldn't be rendered statically because it used cookies based on you know this um thread here it looks like a lot of people have found this error and the solution was to add Force dynamic in app.js um layout. TSX I actually don't think this is the most ideal thing to do um because that's not what we want here because everything is going to be become Dynamic and nothing is going to be cached so I feel maybe this is causing an issue but hey this solved the problem and um if you guys have more information on this like see there's a lot in here um you guys can go ahead and read this thread too I'll go ahead and put this in um the read file the readme file if you guys want to take a look at it um so that you guys can actually read more on this issue if you did see this in the console which is the sheet primitive uh component showing uh class name is does not exist on those props uh you have to go ahead and just remove it from here I don't know why this is even in here but yeah I'm just going to go ahead and remove this okay run npm run build all right cool that fixed our problem get add get commit and then get push just like this all right awesome guys there we go our application has been deployed so the next thing we need to do is also update those uh environment variables that we had right so what you can do now is if you click on this active link it's going to show uh some stuff in here just go ahead and click on add a domain and that's going to spin up a domain name for us and there we go so right now it's actually not going to be live I think so if you open this yeah it there's nothing actually live but that's okay so what you want to do click this link right here that just got spun up and I mean it's basically I'll set but uh what we're going to do is we're going to copy this link all right copy it from the URL uh and then shrink this so just close this right here and then you want to go to variables and you want to change your public site URL okay just like this so edit this right here and you can change it right in here or you can also go in oops sorry guys cancel the redeploy you can also go to the raw editor and you can change it right in here so you have public site URL go ahead and change that to um the new link but without this backslash okay remove that backslash like that and you have https web prod Cypress production of railway. apppp awesome and go ahead and hit update variables okay so um this is going to schedule another deployment so let's go ahead and take a look at that once it's done all right there we go so let's go ahead and click on that and it's going to take us to our application and let's just quickly try to log in and there we go our entire application is deployed so let's go ahead and try to access web prodigies right here try to access a folder okay awesome and there you go everything is up to date and let's click on this great also real time presence uh with superbase is also working and if we go ahead and create a file there we go it creates the file successfully and if we refresh the page we should see three files right there just to make sure our sockets are okay there we go our sockets are also working so we can say digital uh word form I don't know something in information there you go you can see everything works you can also hover over that great you can see the name and if you maybe highlight something let's see what happens here awesome it also shows the other user and you can also find their details here and you can go ahead and send back and forth let's just make sure yep awesome guys and it's also saving great it's saving and it has presence so everything looks great so far um even from here too there you go guys all right great job I really apologized guys since we're running out of time I'm not able to show you how to set up role level policies and things like that for all the tables but I'm just going to give you a quick overview of what this role level policy is and maybe how it works right so what a ro level policy is is basically it is sort of like setting security permissions for each and every row inside a table you can set Ro level policies for updating selecting deleting and all this kind of different operations okay and when a user tries to make that specific operation based on the role level policy you have set it will return or it will prevent the user from seeing that data you can then use that logic and just write something write some code to basically check if there's an error or check if the data has been returned and if not you can reroute the user to a different page so this is how you would set up a new Ro level policy so right here we don't have anything for collaborators so I'm just going to show you what to do you want to go in here and hit new policy and you can see there are two different options which is get started quickly from a template or do full customization so the template is actually more than enough for you to just get set up you can see here enable update access for users based on their based on their email ID so you can check for a very specific email ID and then you can do the following actions you can also check for the authenticated ID so right here delete access for users based on their user ID so you can check o ID equal to user ID so this means only the user is able to uh delete it I think yeah you see here allows users to delete row where uh which the user ID column matches the O ID and then you want to go ahead and hit use template and then you can select maybe a Target rol so I'm just going to put authenticated you can select for what operation for select insert or delete and then all you have to do is in here you just have to return a Boolean expression and once that is done you just go ahead and hit review and this will show you what it's going to look like don't worry if you don't know what this is it's okay you don't need to know all this kind of stuff just go ahead and hit save policy then that will add your policy right here another awesome way to create Ro level security is to go into chat GPT and then just ask it right so you can copy things from here so you see right here we already have some uh Ro level policies created for us which is the users so users can update their own data and everyone can view the user data right so you can maybe check you know how these are done and you can copy this and you can paste it into to chat gbt another really cool feature in superbase is if you go into docs you can use superbase AI to actually look up and give you information all you have to do is click on ask superbase Ai and then you can just ask it something for example how to use in next js13 and then it's going to give you the exact instructions on how to use it just keep in mind this might be a little outdated so you might have to just look at the uh superbase uh documentation I think yeah create client is actually a little outdated because um clearly from our application we use the most upto-date stuff you can also go into um your superbase database so let's go in here to dashboard go into SQL editor and you can also use superbase AI to build you the queries and the RO level policies right in here so you can just tell it give me a ro level policy whatever and then you can go ahead and hit enter and it will do it for you again if you ever get stuck or you need help with something the entire community and myself we're all in the Discord it's in the description just reach out to us and we're all going to help each other uh get the answers to whatever problem you're facing all right prodigies I am super proud of you if you have come to the end of this video and don't forget to subscribe because the next video we are going to be building the best application on YouTube because you are going to pick what you want to see in the next application all you have to do is go to the comment section and put in a request for what feature you want to see and we will make it happen do drop a like to support your boy because I work super hard on this just to give you guys free value and I'm looking forward to giving you more exactly like this all right prodigies see you in the next video
Info
Channel: Web Prodigies
Views: 155,178
Rating: undefined out of 5
Keywords:
Id: A3l6YYkXzzg
Channel Id: undefined
Length: 701min 45sec (42105 seconds)
Published: Wed Nov 08 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.