Build and Deploy Notion Clone – Full Stack Tutorial (NextJS 13, DALL•E, DrizzleORM, OpenAI, Vercel)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
learn how to build and deploy a full stack notion clone using nexs 13 Dolly and versel you'll style the app using Shad Cen and Tailwind CSS you'll also learn how to interact with databases with the efficiency of orms Elliot Chong created this course he specializes in creating comprehensive tutorials on how to build AI powered applications hi what's Poppin I'm Elliot a web developer from Singapore and today here I have a build for you that is a notion plus AI clone so basically what I does is a AI note taking assistant so it's kind of like notion where you have a buin editor where you can type your text and there will be an AI integration with it so let's just show you what I mean so here we can see that it's deployed to versel right using nextjs and you can press get started and basically will'll be using click uh click authentication for this app so we can either sign in with Google or GitHub and we'll press authorize so I'm going to show you how to build this entire thing and deploy it from scratch so you can see we land in this beautiful dashboard right we're able to see all notebooks and all these images today we'll be using learning how to use the open AI di API so if you're not sure do is a uh di is an image generation is a text to image model developed by open AI so we I'll be teaching you how to use your API to actually generate these images that's relevant to uh the links okay so let me just show you an example of how it looks like so we can here we can create a new notebook so you can name anything you want like let's say cats all right so basically what this does it will hit the verel API and this API will be running on the edge so I explain what the edge is but basically this age uh run time will allow you to run uh AI functions for much longer and it's much faster also so the reason why it's taking a little while is because it's trying to generate the image so that takes about a few seconds after you've generated it brings you to this really nice what you see is what you get editor where you can start typing your notes like uh hello and you can even like have functions like italicize it or strike through it or you can make make it into a code block right here's another code block you can type in like JavaScript functions or anything right just to take notes okay but what's really cool about this and what I'm really happy to show you today is you can write you can have ai auto complete so here I can write like uh cats R right and let's say I'm trying to think of something I can press shift a right and it's going to have a AI generated you can see the AI is going to be uh basically trying to complete my sentence so here it generate that cats are mysterious creatures with eyes the same whole world of Secrets right we can basically it just uh it's a very nice AI functionality and be using the versal AI SDK right to actually uh make this streaming feature so you can see that as we type like let's say we can say that uh what else uh cats and docs R and let's try the auto complete are not just pets but also Guardians Of Secrets right so it's a very nice uh cool feature that you can help uh in your writing assistant yeah so be building everything from scratch deploying it I'll teach you how to how to make all this uh what you see is what you get editor you can have like list and stuff so you can really make uh make this into like your daily editor where you can just type notes and have ai to assist you and you can see there auto save feature so all of these notes are saved to the database so you can see that even if you refresh right the the the the data is being persisted and we'll be using a database called neon DB which is a serverless postgress database yeah so if you come back here right if you come back to uh the dashboard right and we refresh the page we can see that the cats has been generated so there's a image that's using Dar API to generate a notebook uh profile thumbnail image to fit whatever name that we have G given it so all this will be using prompt engineering yeah so it's quite a simple short build but I just want to go through how we can build this out today all right so after looking at the demo I'm going to go through a little of what we'll be learning today an overview so we'll be using next gs13 with the app directory for this app we'll be using shat CN which is a tailn CSS Library uh that is very accessible and comes with a lot of nice user interfaces components of the box for us to use and be obviously using open AI for the dly text image generation and also the auto complete uh note feature and number four we learning about the versal H run time so because normally versel free tier allows your your apis to actually run for only 5 Seconds right but then the API like the open ai ai image Generations will take about 8 to 10 seconds so if we use a normal uh versal runtime without the age run time it's going to basically uh time out and then it won't allow your function to run it won't allow the AI to generate the image before expiring the API therefore if you run the versel on this a special age run time it allows us to run the function for much longer and make it much faster okay for our orm we'll be using dzo RM so this is a new orm that is um in competition with Prisma right it's a it's a typescript object relational mapper that allows uh interacting with your SQL databas is much easier and give you type safety and we'll be using neon database as I said just now and for number seven we'll be using Firebase storage to save all the files right so you can see that here all these images that's generated it'll be stored in our filebase app so then we can access the URL through there then we'll be using this for the node editor we'll be using this Library called tip tab uh tip tab node editor right which is another library to basically help you make this kind of very full flet uh very full flet what you see is what you get editor and lastly the versel AI SDK will help us tie the uh front end to the AI back end all right so uh let us get started so here I'm going to open up my terminal and let us do uh let us do to create the next GS project let's do MPX create-x app at latest with the typescript flag so press that it's going to ask us for the project name right it's going to ask us to install the latest version first and then it's going to ask us the for the project name in this case I'm going to do ideation D YouTube so it's just a nice P like AI idation D YouTube so let's just press enter we'll be using ES lint to in CSS we'll be using the source directory and the app router so this is new within xjs the3 and also we'll be uh just leave everything on default and then when it's done I'm going to come back to you okay so now that the next sh project has finished initializing I'm going to do CD adiation Das YouTube then let us do code dot to open up this folder in our vs code editor okay excellent I'm close down this terminal first let's expand the code and what I'm going to do here now first is I'm going to run uh mpm run death right to make sure that the next sh project is up and running so I'm going to come back to my uh browser here I'm going to open up Local Host 3,000 okay and what I'm going to do here is I'm just going to open this up to the right and then the code on the left so that we can see what's happening all right so here we have the next project next project that running and that's good that means everything is working all right so let me just uh walk you through about how the project structure is going to look like so here you can see that it's running on XS 13.5.3 right and so there's this new app directory so you see if you go into the source folder you can see there's this new app directory so how the layout how the navigation is done in Nexus 13.4 is through this special page. TSX so this page. TSX is a special F name right and is is basically doing file based routing so any folder uh inside this app directory that contains this page. TSX will be mapped to the file to the to the route name so because this page. TSX live in the root of this app we can see that it maps to this uh root uh root URL so this basically this file here in this page of TSX map to whatever is shown here in this page so what I'm going to do here is I'm going to uh just return a normal H1 that have a class name of text rate 600 right and say hello world so I'm going to test out TN CSS so because next J didn't really comes with TN CSS when we initialize it and we can see that it works so we know that tawin CSS is working okay so now that we have set up TN CSS and nextjs let's not install shet yet so if you're unfamiliar with shetsen Shen is this very beautiful component Library uh with beautifully designed components that we can copy and paste into our apps and is fully accessible and customizable and this is all built on rtics UI and PN CSS so you can see it really give us very nice beautiful user interfaces right which we can just use directly into our app so to set up Shen right come come back down to your terminal and what you got to do is going to run this command MPX shed uh cn- UI at latest in it so to initialize the shed CN application right then it's going to ask us if you're using typescript we press yes then it ask us which St we can leave as default and leave the color Bas color as default it's going to ask us where our global. CSS is right right now we can see that there this s/ appg global. CS s right this is this comes with the in like the default default nextg project what I want to do is delete this Global s CSS I'm going override it in this uh in the shn file so because we want shn to handle all selling for us so we can tell the global sour CSS lives in sourcea global. CSS okay Enter and it's going ask us if you want to use CSS variables press yes and it us where our Tailwind config is so in this case we we using typescript so the tailn config actually lives in T.C config.inc config.sys as default and the import alas for utilities as default and lastly we're using react s components press yes it ask us if want to write the configuration to components. Json so it's just writing the configurations to a file to be saved by shm okay perfect so now we can see that uh there this new components. Json file here and basically it contains all the it contains all the configuration that we just entered in the terminal all right so how do we actually start using shs yet so imagine I to use like a button component right so for now I'm just going to uh I'm going to restart the server right and then let's see what's what's happening so let's come back to page. TSX all right so right now it's uh it's it's Bri color so everything is been reseted but let's say I want to install uh the shetan button so whenever you want to use a new component within Shen you have to manually install it and this is a good thing because you only install the components you need and the components you don't need will not be built into your app as a final production okay so you want to install a new button you do MPX sh uh sh cn- UI at latest add button so you can add the button component it's going to ask you if you want to confirm so just uh just install the button it's automatically going to install it and let's see where it installs it in so we can see that under Source app we can now see there's a new components folder if you go into components right we can see that this is uh there's this UI folder and within the UI folder is this button TSX so this button. TSX is basically what is generated by Shen right it uses this like called class variance auality authority to basically give us the styling for using TN CSS to give us the styling for uh different variants of the pre-art button so you never really need to go into this file to touch the buttons right all you need to do is know that this file exists and you can use it so I'm going to close it out and how do you actually use it so instead of returning a H1 I'm going to just in return a button and we can see that this is automate imported from ui/ button so let me just press enter Auto Import and going to say click me so let me save that and now you can see that the button is showing up so we have successfully installed sh CN all right so now that we have set up shat CN let's now go on to next step of uh installing our cler so cler we'll be using clerk.com uh for this for the authentication part right cler is a really it's a beautiful framework it's a beautiful library that makes authentication so easy and simple so I'm going to teach you how to use it so come down to cl.com and you have to log in to the account or sign up and after that you can come down to your dashboard so in the dashboard you're able to see all the different apps that you have made all right so in this case I'm going to add a new application and I'm going to zoom in here and we're going to basically name it uh ai ai dation all right YouTube okay and then it's asking us how will user sign in so you can choose email as default I'm going to turn it off because I only want to let them sign in using Google and also uh GitHub so YouTube uh Google and GitHub for now and you can choose and T Go on whatever methods you want them to sign in so then after you have chosen just press create application and you will create a it'll create the secret keys for you to use in your application so what I'm going to do is I'm going to come down here and I'm going to press continue IND dos CU we're using next 1 right so continue Indo so let's follow the instructions on how to actually use this uh use this Library so the first step is to install cl/ nexts so I'm going to install it I'm going to follow the instructions so come down to my terminal I'm going to do mpm install at clerk / nextjs okay so now that we've installed it let us actually put out environmental keys so come down to your file directory in the root file folder all right on the root folder create a newv file and one more thing to know is come down to your gor and I want to add the EnV extension to the gor so that this is so that the environmental file does not get committed into your git repository and does not get pushed up to GitHub later on right so because you don't want people to see your secret keys because they can easily abuse it therefore we're adding this.v into the G ignore okay so let us now continue pasting in this uh these two keys into the EnV so we'll place it in and save it so now we have this uh next public uh next cler public cler publishable key and the secret key now let's go on to the third step which is to mount the cler provider right so we need this cler provider to wrap our entire application to give the entire application the context of who's the currently loog in user and whether they even Lo Lo in so come down to layout. TSX right so this layout. TS is basically what WS the entire application and what I'm going to do is here I'm going to just import import uh from at cl/ next year so this is a li a library we just mpm installed just now and I want to uh import this CL provider right then I'm going to come down to this return I'm going to just wrap the entire application in the CL provider just wrap it here and save it all right so that's good and now uh since we're in layout let me talk about this metadata so this metadata is just uh what DET takes what is shown on this uh you can see that there is this the tab is create next app right so this is what corresponds to the title tab the tab title so you can just change it to let's say iation or YouTube then you can just delete the description so if we save it now we can see the tab name has changed to match the idation YouTube here okay that's good so so now let's continue following on the cler documentation there's a few more things that we need to do okay so number four is protect our application so now we this protect our application we need to create a new middleware dots so this middleware dots is a special file within nextjs that basically allows code to run before every request so before you navigate to any page or you try to hit any end point right it will run this middleware TS a code simple first right so we can use this middleware TS to basically control a whether these users locked in and if they locked in we want to protect certain pages so what I'm going to come down to do is come down to your Source folder inside the source folder create a middle middleware TS file right and going just copy in the code from the CL documentation in here so basically what it does is import this off middleware from the library and then export a default function here so this basically protects all the routes right it protects all the route so that anyone who's um how say uh are not not loged in they cannot access any routes and they are forced to sign in right so we actually do not want that to happen because we want to basically allow this public routs we want to allow a non-login user to to access this uh SL drop so this SL drop is like the homepage so if you can see the in the deploy application right we can see that this is a SL the homepage right where want all everyone can access therefore we're going to basically add this slash to the public routes array okay so now that we have set up middleware dots let us move on so okay so for this sign up sign sign up Pages I'm going to come down to my source directory come down to app and create a new folder called sign- up then within the sign- up let's create a two angle brackets dot dot do sign- up right then within this folder we can finally create a page. TSX okay so for this page. TSX I'm going to import this uh import this default sign up component so they already pre-art a UI for us so I'm going to save it okay so we have copied in the default sign up component and now let's do the signin page so come down to your app uh app folder again and create a sign sign Das in folder within that do bracket bracket do do do sign Dash in right then under that we can just actually this should be a folder not a file so let's do that so it be a folder called d uh bracket bracket sign Dash in right then inside here we can do a page. TSX and let's create a copy in the default signin component from cl/ nextjs okay then now we need to update our environmental variables right let me just zoom in here a little right so we need this environmental variables to basically tell cler which is our sign in and sign up pages so come down to your EnV file again and now under the CL uh secret key let us do let us copy this four variables in right so these four variables basically tell cler which is your sign in and sign up URL so we have ma the signin URL to/ sign up sign in and sign up right following the folder structure here so we leave that as default but here we can also configure uh what happens after we sign in and what happens after we sign up so after we have signed in let's redirect them to the/ dashboard page and after they have signed up we so let us lead them to the/ dashboard page so let's save that and now uh if you come back to our Local Host 3000 right so Local Host 3000 right here is our default page but now if you go to slash uh SL sign Das up right we can see that it BR brings us to this custom component here so this maps to the sign up page uh here that we have this a sign up component here okay so that's good so one more thing here I'm just going to Center I'm just going to try to Center this component in the middle of the screen right so I'm going to just return a a diff that just have a class name of position absolute top of half left of half negative translates X of half and negative Translate it Translate Y of half and then let me just return this component so if we do that now we can see that if you remove that semicolon right we can see that the component is centered in the screen right and then we can also sign up and just continue with GitHub so I'm going to do the same with the sign in component so I'm going copy this come back down to my sign in component right and then I'm me just do the same return this okay but this time will be the sign in component so let's say this and now you can see that if you come down to sign in page it's also properly centered in the screen so I'm going to come and sign up and basically come down to continue with my GitHub or Google account okay so then it's going to just redirect me to the GitHub o page and since and now you can see we can see that after we have signed in it brought us to/ dashboard exactly what we asked cler to do okay so now that it has redirect us to the dashboard let us actually not do that first I want to actually finish up my Landing page right so you can see in the deploy application there's this very nice uh big title with this typewriter effect so I'm going to build out this page first for us okay so I'm going to just close down all my tabs here come down to our page. TSX so this is where we rendered this button so I'm going to basically make that into the landing page so the first thing here is I'm going to do is uh I'm going to just uh delete this and want to return a a diff right sorry this will be a diff so this diff let us give you a class name of a b gradient from to right right so it goes to the right and let us give you a mean height of screen from rows 100 to T to T 100 right so this is from like this Dash right so if you save it right now you can see there this nice gradient from this rose color to this K color okay and one more thing I add here is you can see that this a very greeny R slight greeny effect that I really love right so I'm going to try I'm going to show you how to actually add this greeny effect so if you come down to your uh Global s CSS Global CSS right underneath close on this layer base right so these are all basically shed CN and TN CSS configuration right so what want to do is um come down to this create a new class called greeny it's a custom class and we have a background image of of this uh this URL so let me just copy from down here right so don't worry I'll give you the link I'll give you uh a page bin to this background image but basically this background image is just a a green effect right so this background image if you like if you inspect it it's going to be greeny effect so uh we can just use this greeny and in our app so let me just save this come down to our page here right so right now we can see that it's not grainy right so if you add one more class here that says grainy and let's save it now you can see there's this new greeny effect on our app yeah so that's a very simple and nice touch to make the UI a lot nicer okay so within this diff let us have another diff that wraps to make everything centered so let me have a diff here and the class name will be position absolute top of half left of half negative translate X of half and negative Translate Y of half right then this will Center everything here and within it let me just put a H1 that has a class name of uh let's give it font semi B Tex 7 XL to make it huge and let's Center by doing Tex center with h the H1 let's just do AI uh note taking assistant right then if you see that now we can see there this AI note taking assistant in the middle of the screen so let me just put uh this green color in the note taking right so make this note taking green color to do that I'm going to wrap uh this note taking in a span right so I'm going to just take this note taking here and put it in the span okay and within this span let us give you a class name of uh text green 600 and font Bol font Bool okay so now we can see this AI take note taking assistant much nicer now okay right we can see that this looks looks nicer and let me just give you some space so in front of this assistant let us put this space block here so that it shows up nicely okay so underneath the H1 uh let's have a spacer so just do mt4 sorry mt-4 so this is just a MTD element with a margin top of four so then we can put our a typewriter title here so for this typewriter title let me just put a H2 here and give a class name of font semi board text 3XL text of Center and text slit of sorry text- slit of 700 and here I just put AI uh forward save it so right now we can see that it's just a normal text right but we want this we want this like a nice type rer effect so let's create a separate component for the typewriter effect come down to your directory come down to your components right right so we can see the component has a UI folder but we don't to create it within the UI folder because whatever in the UI folder is handled by shn we want to create I would think within the component folder itself so inside components let us create a new uh file let's just call it typ writer title. TSX okay then for this type riter title let's actually do tsfc so this tsfc is a is a extension snipper in vs code that give me the typescript react Arrow function exper component right so is under this extension called I think es7 snippers or something yeah uh sniper yeah simple extension Snippets you can install that for yourself so it will give me this uh command right and then with here let's actually make the typewriter effect and we have a library for that right like everything in JavaScript there's always library for whatever things you want so let's install the library for the typew writing effect so do mpm install typewriter D effect okay so once we have installed that let's actually import it to use it so uh import type Rider from type Rider effect okay so then with here I'm just return the type Rider okay let's pass in the op some options right so we want it to Loop to Loop indefinitely forever and then here we can actually uh basically tell it what kind of things to type out so on in it we can just um destructure out this typew riter uh we can actually Dru we can just take the type typew riter right and what you want to do with this typew riter right so we have a lot of different things we can just do typewriter do type string so the first string we want to type is um basically we can just choose a emoji and a tag line so in this case I'm just going to just copy this TCH line in right so you can write whever you want right I'm just going to put this here so the first thing is it's going to type out this supercharge productivity right so I'm going to save it first and then come back to our page. DSX and I'm going to import the typewriter title uh component here so if you save it right now we can see that okay must be either now so one more thing we need to do here is come back to your typewriter title we need to make this into a client component so because this next Yer every component is by default server component right so now we can see that if you refresh it should uh type type it out right but we haven't started it so to actually start typing we have to do do start so if we save it now we can see that you should start typing let us refresh the page and let's see what it does and now we can see it starts typing and then because it we put loop as true it's going to basically loop back delete all the words and just loop back right so let's actually add more stuff let's say we can do so after he has typed let us just pause for maybe uh pause for 1,000 milliseconds which is 1 second so after pausing let us delete all and then we can do the next type so we type string again so then we can type out another thing like let's say uh copy this in type out AI power insight okay so let's save it and yeah that's pretty much it so you can add however more like imperative uh typing you want so we can type then pause and delete then type then basically you just have this right cool typewriter effect where you're just typing out the different tag lines you have for your application yeah so that's pretty much it it's quite simple for the the homepage so let me see if there's anything else that we need for the homepage okay so now let's actually add the button to go to the dashboard so underneath the H2 let's have another spacer called mt-8 so it's another empty diff with the margin top of eight right to give you some a margin here and let us have a diff here uh that has a let me see let us just remove that diff actually so below the spacer right so I messed it up here so let us actually have the link so this link come from next Das link right we want to basically link it to the SL dashboard and inside the link let's show a button so this button will have a class name of BG D green- 600 then within it let us just do get started right and then let save it and so now we can see there a new button here okay so let's Center this let's Center this in the middle of the screen right so what I'm going to do here is I'm going to just wrap this in another diff and this div will have a class name of flex and justify Center so this will just Center the button in the middle of the screen and let me just add the icon right you can see there's icon nice icon here so for icons for the icons will'll be using this package called Lucid react mkm install Lucid D react so it's a icon Library if you have not seen before Lucid if you go to Lucid def it just provides us with Rand nice UI uh icons for us to use within our application okay so inside this button like just beside this get started let us have a a call Arrow right so let's import this Arrow right icon from L react so import from Lu D react so what try import the arrow right icon okay so this Arrow right let's give you some styling of margin left of two width of five and height of five and we give a stroke width of short WID of let's say sorry three three so now it looks much nicer here with a button so if you click on this we can see that it will lead us to the dashboard right which we have not created yet so that's good we have created the uh landing page so that's good all right so now that we have completed the homepage let's actually work on the dashboard page so come down to your directory sorry come down to your folder here and come down to your app and let's actually create a new folder called dashboard then within the dashboard let's create the special page. TSX so then this will map to whatever shown here so let's do TS R FC to create the react component and let's just name it to dashboard page so if you save it now we can see the dashboard page showing up here okay so let's actually build out the user interface for the dashboard so I'm going to come down here I'm going to delete this I'm going to return a uh react fragment and within here let us have a a diff that have a class name of grainy so we have the grainy background again just now and a minimum height of screen and if you save it right now you can see the greeny background showing up here all right within the within this diff let's actually have another diff uh sorry diff they have a class name of a Max width of 7 XL and margin X of Auto and also padding of 10 within this second inner diff let's have a basically uh a empty diff with a height of 14 so here just another spacer empty D with a space of uh height of 14 just to space out the element a little right and then let's have another diff in here and this diff is going to what is going to be showing the let me go to the deploy app it's going to show us the this my notes the back button and our user profile here okay so for this diff let's give you a class name of um Flex justify between items items Das center right then when we on the medium screen we want it to be Flex Dash row but on the small screen like mobile we want to be Flex column so we can see that this a responsive element to it so we can see that it's responsive like this okay so come back down to your local host uh let me just move this here okay so within this uh within this Flex uh container let have another diff that have just uh with a class name of class name of flex and items Das Center and within this item Center diff let us have a link right this link come from uh come from next SL link not Lucid D react right come from next SL link let's have a HRA to the slash so this is the back button so let's import the button and let's just do back so let's save it and now we have this back button showing up here okay let's give you some styling uh I'm going to just have a uh within this button let's have a arrow left icon from lucd D react right he has a class name of margin right of one width of four and height of four so now we can see that it just adds arrow to the button and then for the button let us give a class name of BG green of 600 all right to match the theme of our application okay then below this link right below this link let us have a another diff right this has a diff of it's empty diff of with D4 so it's just not spacer element right and then here we have a H1 that says my notes so give let's say give this H1 some class names of text- 3XL font Bo and text- g- 900 so we save it now we have this uh it just put it side by side the H1 let's have another another spacer diff of with das4 so it's not empty diff and let's here let's put a user button so this user button you can see is imported from cl/ nextjs so there is a pre uh pre-built button component for us right that shows us that allows us to see our profile image and manage accounts and even lock us out if you want to here okay so that's pretty much it for like you see this top top bar here right so you can see this on here the button is a little smaller so we can do that here by coming into the button and let's pass a sizing of SM here so we just make the button a little smaller okay that's good so now that we have that let's actually build the spacer and the The Notebook list all right so underneath the underneath the user button we have this diff right and then we come down to this diff again right so basically above the two closing diff we have another spacer uh height d8 spacer and then here we have a uh separator so we this separator comes from Shen so let's add that component so MPX Shen at UI at latest at separator so you just add the component into our project then we can import it import it in here so let's just do after you finished installing let us do separator and now we can see that it imports from ui/ separator and then we'll just have another spacer of -8 so right now we can see that there this very F line I'm not sure if you can see on camera but uh there's a F line of the separator and then underne the separator here is where we will uh list all the notes and the images of course so it's all this list all right so here is I'm just going to uh just show here so I'm going to show a diff with a class name of diff with the class name of text Center and inside here inside the diff let's have a H2 that says you have no notes yet so this H2 will have a class name of text just Excel text Gray of 500 so if we have no if we have don't have any notes yet we'll show this so later on this will have to be uh conditionally rendered condition conditionally rendered I spell it right conditionally okay whatever yeah so later we'll get the notes and we'll just conditionally render this okay so we have set up the simple dashboard and now I'm going to try to move on to help setting up the database so that we can actually start creating notes and fetching the nodes right so for the database we'll be using a neon DB so and we'll be also using drizzel to interact with this neon database so come down to Neon dotech right this is a domain and you might need to sign up or log in if you have not done so so you have to sign up into the the database so by default it creates gives us a free database to work with right so you can then create a new project for like a free free database so for the name let me just do uh ideation Das ideation D YouTube then just choose default postr version and choose a region that's closest to you in this case I'm closest to Singapore so I'm going to put Singapore and then just leave the rest as default and just create a project so then this will give us a database connection string right then we can copy this in so let me just copy in this URL right then we can actually close down the console actually we don't need that anymore so come down to your EnV file right and we need the database URL so let me just do datab base underscore URL and just paste this in right so make sure there's no white space right right and one more thing you need to add here is at the end right at the end of this string right I want to help add this uh question mark SSL mode equals require so we need this SSL mode equal required because we're going to be connecting to our DZ RM and we need to be secure so we add this here so make sure you have that added in then now we can actually start making the drizzle orm uh to actually interact with this database so drizzle orm so if you're not sure this is just a object relational mapper which allows us to interact with our SQL databases to very nice typescript objects okay so how what we do is first come down and just actually close this close this tab I'll show you I walk you show how to actually install result so come down here and just do mkm install drizzle dorm right drizzle dorm come down to your folder okay and we'll create a new Under lip right so lip is for Library so basically any any files that is like any utility files any folders that we need to prepare to use beforee put in the lip so create a new folder under called DB so it's going going to store our database so inside here we have two files one is called index.ts and one is called schema. TS so this index.ts is going to contain the drizzle configuration so initialize our drizzle U drizzle object and the schema. TS is where we Define our database schema like all the tables and the columns so come down to your index.ts for the table and DB and let us actually do it start configuration so one more thing you to install is mpm install at neon database SL serverless right so sorry ignore the rest we just need this at neon database serverless because we need basically this is a how say is is to help us connect the neon database to our result orm so after installing that let's import a few things so the first thing we import from the at neon database serverless is we import the neon object itself and also the neon config okay and the other thing is we need to install import drizzle right actual drizzle so we import from drizzle RM import from drizzle rm/ neon d HTTP okay so let's import the dzo object here so then now we can do neon config do fetch connection cache sorry fetch connection cache equals to true so basically we just want to cach all the connection so that it doesn't like repeat uh creating new con connection every time we reload the page okay so then we're going to check if not process. env. database URL right we got then throw a new throw a new error saying that database URL is not defined so we need this EnV variable that we have defined in here so if there isn't this variable it's going to True an error all right so then lastly we can just do cons SQL equals to Neon invoke the neon function and we can invoke it on the process. env. database URL okay then lastly we can just export a DB object which is the drizzle right then we just passing the SQL uh SQL object into the drizzle function here so this DB is how we got interact with the thing so we can do things like uh db. select from from where something like that so this is how we build the SQL connection strings to get back results from our database so now that we have this let's actually Define the schema so what kind of tables will we really need it's a really actually really simple project we only need in this schema. TS we only need to Define one table okay so before that let's import some utility functions to help us Define the table so be importing from drizzo or/ PG dcore so PG is for postgress postgress core core and we import a few things like PG table so we need this PG table to Define our table so let me just do export cons uh dollar sign notes okay equals to PG table and then basically we giving a name of notes so this notes uh name is going to be what save between within the post database this the table name right and then we'll pass in the configuration object so this is where we actually pass in all the columns so first we have ID column it's going to be a Serial right so we this serial we imported from PG core right can see it's Auto imported so with zero and basically the inside the name right this is basically the name the column name within the database right it's going to make it into a primary key so then we also have a name field which is a text field also from PG dcore uh PG PG core and will give you a internal table name of name I'll make sure that this is not now lastly we have a created uh not lastly but one more thing is created at so we have a typ time stamp right will be time stamp so import this from PG core Also let's just name it to the same thing created at do not now so make sure it's not now and by default we want to basically default it to now yeah that's pretty much it so whenever the a new road gets created this created at fuel will default to this uh to the current time span time stamp then lastly not lastly again sorry so image URL so this is where we store the open the D image right the Firebase image so this will be a text that just maps to image URL yeah and then for this we have a user ID course we want to know which user created the note right so this is a one to many relationship so let's do text is a user ID and make sure this not now so this user ID will come from the cler user ID and then lastly we have the editor state which is just a text of editor State yeah that's pretty much it so this editor state is basically what I start like whenever we create a new note right we we save the state of the whatever state of the content here of what we have written yeah so like let's say we come into our cat right so everything here is saved into the database into this table called editor State yeah so now that we have defined this schema right let's actually one just last line let's just export a type called notes type so we might need the types script type for this PG table right so we can just do it by doing type of uh dollar sign notes so these dollar sign notes come from this PG table and we just do infer select so if we do that if you hover over this note type now we can see the types script type so we can inspect the name user ID and all the ID so this is very useful later on when we are actually doing the uh UI and the typescript definitions so let's save that so now that we have defined the schema how do we actually make sure that the schema is synced with the database in the neon DB Cloud so for that there's one more tool called uh mpm install uh drizzle Das kit so let me just uh tell you the difference what's the difference between drizzle RM and drizzo dkit so uh drizzo orm is what we use to interact with the with to the database right basically like within our app we can programmatically in use the drizz RM to interact and fetch data but drizzle uh drizzle kit is not uh it's not necessary but it's a developer tool to basically help you migrate your changes let's say you added a new table or you add a new column you have to make sure that the column is synced up with the neon database then you can use DZ kit to actually inspect like uh push your migrations up to the database and also it gives you a studio like a web Studio to view all your database and all your rades okay so now that we have installed DRZ kit let's actually uh create a configuration object to actually make sure that uh we know where this configuration file lives in so come down to your uh to your file directory again okay and we have to create a in the root file like in the root folder everything outside of the source create a new uh f file called drizzle. config dots so it has to be drizzle. config.yml the type of config from drizzo dkit so this config object will tell us like what kind of configuration is needed and now let's actually uh do export default right and this object is going to satisfy the config object so now we can get some very nice like type annotation right right here we can do control space and we can see all the all the different things we need for this uh configuration object so for the driver right we can see we we using postgress and then for the schema right this schema is basically telling where where does the schema F livt in so right now we can see that it lives in uh relative to this file it lives in Source slash Source SL lip ddb schema. TS so let us do that so we'll do/ Source /p/ DB schema. TS okay and then lastly for the DB credentials we pass in the connection string to be the process. env. database URL right and make sure that this exists so one issue you're going to face is that this is not going to exist right why because next y thing right it automat loads in your EnV but it only loads the EnV file for any file that's accessing it within the source directory so any folder that's trying to access the EnV outside of the source directory next just does not handle that so this D.C config object and we can pass in the path equals to do EnV so it's just basically telling this file where the the the EnV file lives in so that it's able to Lo load in this database URL for this uh variable to make sense okay so now that we have that last thing we need to do is come down to your TS config.js and we have to change the target to es6 so just some weird issue within dzo but you just have to change it to es6 for this to work so now that you have done that everything is going to work perfectly so now you can come back to your terminal and push your your schema up to the database so to do that we do MX drizzle dkit push PG so colon PG so if you enter this it's going to rein the schema right so it's going to see that it's going to rein the configuration file this drizo config.txt a studio right so if you run this there's going to be one error it's going to say that actually one we need to install one more module which is the PG package right so to actually interact with the database so we do mpm install PG postgress so after installing that we can actually run the MPX studio right d kit studio and now we can see that is it will show us all our different tables so let me just pull this up sorry let me just pull this up here okay so now we can see that we have this notes object notes table so we able to inspect all our different tables and right now we can see this notes is ID name created at image URL user ID and this all maps correctly to the uh schema schema that we have defined here so now we have ensure that the database is set up and we have pushed our schema up to the neon database so that's perfect you're doing well okay so the next step after setting up the database is I'm going to basically create this uh this basically uh this notes to basically allow you to add create add a new notes so the UI to add a new note so I'm going to show you how to make this a uh this new notebook so when you click on it there's a a dialogue a popup that allows you to enter the name and you can press create to actually do the back end call so for now let us just go back to our dashboard page dashboard page and then let us actually do put the dashboard the add component here okay so let me just see how to actually start all right so here just below the below the diff right for the you see this conditionally rendered you have no notes just below here this is where we display all the notes okay so here I'm going to create a new diff a new diff sorry a new diff they have a class name of so it's going to be a display grid so it's going to have a grid layout so we have let's do grid then when it's small screen above we do grid calls D3 then when it's medium we'll do gr- call- five then when it's just on a small screen like on the mobile screen we just do g c of one and lastly we have gap of three and then within here is where we display all the notes but before all the notes right we actually can add a create a note dialog dialog so this is actually what isown here like this you see this borded new notebook button here where you can click to add this to have this popup so let's create that component so come down to your folder under components that us to create sorry not under UI make sure it's under components okay so let's do create note dialogue dialog. TSX do TSR fce okay so for the create note dialogue let's actually make it into a cent component use client all right and then and then and then let actually let Let's do let's see okay so to actually make the dialogue we'll be using the shn dialogue so uh to do that let's do MP MPX Shen install sorry npx shnu latest at dialog so this dialogue is like the popup thing when you click on the button okay so while it's installing the dialogue let's actually do the styling so we won't be returning the div but be returning a dialogue so we import the dialog from ui/ dialog and then within this we have a dialog trigger trigger so this dialog trigger is what basically what triggers the popup right so let us have a div here sorry div let's have class name of Border Dash dashed border dashed a border two border green 600 height of full rounded of large okay and then we'll have items Center just def F Center and on the small screen we'll have make it Flex uh column right then when it's hover will give you a shadow of Xcel and then transition sorry transition then on Hover we have a negative translat y of one and then Flex row and padding of four so it's a very long class name it's very long class name but let's just do the stying now I'll show you how it looks like and explain more to you within the diff here let's have a a hit to that says new notesbook let's give you a style name class name of font semi bolt uh Tex green 600 there 600 and when it's small give you a margin top of two and then above here let's have a plus icon a plus icon right with the class name of width six height six Tex green of 600 and and give a stroke width of three so if you save it and then let's actually import it so come back to your dashboard page so me close it all out uh dashboard let's actually import this create note dialogue import and let's save it and then now we can see that this uh there this thing that's showing up here so I think that's a mistake in my styling right so here uh items D Center justify the center okay Flex call right and the reason why is because yeah I forget to add a flex so let me just add a flex here okay yeah so you need add a flex so it's just border Das tool and just basically give you the border and just align the two uh elements within inside so when it's small screen you can see that is uh when it's big screen stack on top when it's a small screen it's stack like horizontally okay that's perfect okay so then when we click on this right there that's supposed supposed to be the popup right so this is the dialog trigger is what triggers the popup so let's actually make the popup so we have the dialog uh content so this dialog Conta come comes from the/ UI dialogue and then inside the dialog contenter have a dialog header right this dialog header uh should have let's put in you can create a new note by clicking the button below so if we save that and we click on it now we can see that there's this dialogue that's popping up right now so looks very nice okay so let's actually continue so underneath the dialog header so wait so within the dialog header this should actually be wrapped in the dialog title okay here so the create new note should be inside the dialog title and then within it the below the dialog title we have a dialog um description okay this dialog description will have uh we can put like uh you can create a new note so this should be down here and the dialog title should have a new notesbook so let me show you how it looks like so that it makes more sense yeah so here new notebook is the title and then the description is the create notebook by clicking the button below okay so that's good and then underneath the dialogue heer right so this is where we put our input FS like here we can see that this is input F sorry we can see this input F so you can see there's this input Feld the for the name and the the buttons to create or cancel okay so under the dialogue header we have a normal form element okay inside the form element let us uh uh let us just put a um a spacer with a height of four and then for this form let give you some class names of uh sorry not the form the form doesn't need any So Below uh above the spacer right below the form right we have input fi so this input comes from shat again so let's do MPX shn at UI latest at input so this is the input Field St by shn so let's wait for that to install and then we can imported input from the/ uiinput and let us actually give it a placeholder of name dot do dot so we save it right now we can see there's a form that has a name f here okay that's nice then underneath the spacer right underneath the spacer let's actually put the two buttons right so have a flex. item Center so this where we got put the two buttons so the first button right sorry this first button will come from the this first button will say cancel and then the second button will say uh submit uh create here and for the first button here we have a type of reset and a variance of secondary okay and then yeah and then for the create button right we'll just have a just put a just save it first so right now we can see this is create and cancel here let's give this button down here styling of VG green 600 all right so it looks more on brand and for this uh items Center so just between let's give it a gap of two so that it's space out a little more okay that's perfect that's perfect so basically what we want to to happen is whenever we uh let's add type of submit so whenever we submit we want to actually create a back end right so let's actually create the state to actually hold the input element here so we have already made this a use CL so then now we can do a create a new state called input and set input to be a react. new state okay so then we going bind it into the input field so let's have a value of input and on change let us do e we'll do sets input e. target. value so we have we make it a control component so that right now we can just uh enter and then it just uh it will be bounded to this input variable here input state that we can access all right so uh I think that's it for now for the front end so now I'm going to try to show you how to create the back end uh to actually create a new note whenever we click on this create button all right so let's actually create the back end uh end point to actually generate the images and the uh the basically the thumbnail for the image when we submit this name to the new notebook so I'm going to clear out all my tabs and then actually create come down to app create a new folder called API and then create a new folder within it again let's call it um let's see what do we want to call it let's just create create notebook right and then within it we can create a ro. TS so this root. TS is a special file right so this root. TS it will look at the F folder structure and map to a rest end point so we can basically this this file will map to/ API SLC creat notes book right so this is the end point that this file represents so then we can export a async function called post right and then this post will will have uh a request a standard web API request object where we can actually get the request body all right so I'm basically I'm going to do is I'm going to just take the uh cons body uh cons body so the request body is going to be await request. Json all right so this will convert the request into Json and we can access the request body from there okay so then we'll get out a name from the body name equals to body right so later on we'll be passing this new notebook name into this endpoint here so we get back the name so before that let me actually check whether the user is authenticated because if the user is not authenticated we don't want them to be creating a new notebook so let's just get get back the cons equals to off so this off comes from click slj is a server side function that will return us with the uh user ID here okay okay then we'll check if not user ID right that means they're not authenticated some we will just return a new next response right sorry new next response that says unauthorized pass in a status of 401 okay so now let's actually create the image the D image right so before that let's actually create a new a new library so come down to your Source SL lip within the lip let's create a new file called open ai. TS so this is going to hold two functions mainly so the first function is going to be the first function is going to be a a a sync it's going to be basically get image uh generate image prompt okay so and the second function is going to be obviously export async uh this second uh Endo is going to be for the actual image Generation by the DI API generate image Okay so so let me just commment this out first uh sorry this will be asyn function and this will be also an asyn function okay so for this generate image prompt it's going to take in the the name the prompt which is a string it's going to basically take a name like let's say we put in a name like a math right so we run a new math notebook what it's going to do this function is going to be uh responsible for using the open AI API to generate a very descriptive text for the math notebook so it will generate like uh oh a a thumbnail a thumbnail that uh has a bunch of color colorful numbers and circles things like that basically it gives a very nice uh very detailed description and basically take this description this uh this prompt this description and will then feed it into this general image because for the dly API the more specific and the more detailed your description the better the image result is going to get back so therefore we need this image prompt function to actually generate a very detailed description from a simple name all right so to do that let's actually uh configure the open open AI so come down to your terminal and let's install the open AI package so open ai- so this open a-h is a special uh version of open that allows you to run on the versal H end point uh versal H run time to make it faster and there U allows your function to run for longer okay so yeah so then let's close out the terminal and let's uh initialized open API so we need a few things import two things from open a-h so we need uh the first thing is configuration and the second thing is the open AI Epi okay so for the first thing we'll do is Con config will configur uh configurate to be new configuration new configuration and we pass in the open AI API key so how do we get the open EI API key so come down to your browser and just search for open EI API key okay come down to the first link here and then just come down to menu and then your API so first you need to obviously register for the open a account yeah so come down to I think overview and let's actually get started for developers and sign up if you have not already and or sign in if you have an account okay so after you have uh sign in to the dashboard I want you to come down to your personal like this uh that manual dashboard and then come to view API and then here you can then create a new secret key and you can name it adiation D YouTube so create the secret key right then it will create a secret API key for you and copy the key so after you've copied the key you can just close it out we don't need this anymore so come back here come down to your EnV and let us call open eore API key and let us just place the in so there's a secret key so let's save it and then now come here and passing the API key to be process. env. open EI open ei- ai- key so make sure this matches whatever you have here spell it correctly so this one spell it correctly okay so then after this we can actually initialize the cons open AI equal to new open AI API passing in the configuration object so now this open AI we can call different functions on it like let's say create check completion or we can create image here so this create image is what is going to be used for the D image gener okay so then come down here for the generate image prompt for the generate image prompt so we take in the name right so rename it to name so this name is The Notebook name right so let's actually create the uh description so put in the TR catch block and then basically what we're going to do is we do cons response equals to await open EI do create chat compl completion we're passing the model to be a GPT -3.5 dturbo and then for the messages we have an array so the first message will be a system message basically from the AI to tell you what what is meaning to do what it's supposed to do right so we tell you that uh you are a creative and helpful AI assistant assistant capable capable of generating interesting thumbnail descriptions for my notes okay then we tell it that your output will be fed into the D API to generate a thumb nail okay then we just tell I want uh the description should be minimalistic and flat stop so you can just basically prompt the different like and prompt the AI to give whatever you want so we're just telling it that it's able to uh output a description of a interesting thumbnail and then for the second message here is where we actually pass in the promt so we have a row of user and then for the content we can just say that uh please generate a thumbnail description for my Note book titled and Fe the name so this names come from this parameter which come from this uh frontend U that will pass back to the back end later okay then once we got this response we can just do uh let us do uh cons data equ goes to await response. Json so convert the response to Json then we do cons image description equals to data do choices sorry do choices index zero. message. content all right then last you can just return the image description as a string so to tell type script that this function returns a string and if there are any errors let's just do console do uh log error and just return the error so let's save that okay so actually instead of return let's actually just throw the error okay that's cool so that's good so now we got the image description so let's actually try this out so I'm going to come back to my root. ts and we can actually test out the image description function that we just written so let's do cons image description equals to await General image promt pass in passing in the name from the body and for now let's do console. loock image description okay and then we just return a new next response response that sorry response that says Okay okay so I'm going to conso the log and we're going to try to link it up to the front end right now okay so for the front end to actually hit the back end and point I'll be using a library called react query so it's just a a library to manage a client and server State and actually mutations to the server that mean like hitting the end points or like quaring something from the backend API so to install that we'll just do npm install at 10 stack right/ react D query right so this react query will help us just manage the state within our application right to hit the end points to actually mutate mutate and get back the results so to actually use that let's come down to our directory come down to our components and let's actually create a new component called providers provider. TSX so let's just to TSR FC this is going to be a client component all right so we have this client providers component it's going to WP our entire application so we're going to import a few things so we'll import uh from at 10stack react query so we'll import two things the query client and so the query client provider so the first step here is in the props we receive the children that means it's the application that we are wrapping around it will be a react Noe so let's destructure the children from the props and let's actually just rep the uh query client provider uh we'll rep the query client provider here and then we'll just put the children here children okay so this qu client provider requires one thing requires this client so how do we get this client we get it by just doing cons quy clients equal to it goes to New query client like this and just have to pass in the query client here yeah quy client okay yep that's pretty much it uh let me just spell this correctly query client oops query Cent okay come on okay so let me just copy this here all right so basically we just wrap the entire application in this children so the the reason why we need this provider is because let's let's imagine right you have one page that is fetching a list of notes so you fetch all the notes from this one page and you display on the front end here but let's say you navigate to another page and you are fetching the same end point you're hitting the same end point and getting back the same notes right instead of basically uh doing the same request twice and hitting the end point twice react query will notice that hey I actually just fet this query about like 5 seconds ago right I I can just save the request by just reusing the same result from the first uh query so basically it will just store this uh result in a cache and then it will just use this cach instead of hitting the end point again so that's why we need this query Clan provider such that every component within our react Tre is able to have access to this cach so I hope you understand uh this concept in react query okay and then we can just come down to our layout. TSX that wraps our entire file and we can just uh wrap our let's wrap our body right with the provider provider Provider from our components wrap this body and let's save it then now we can use the react query so let's actually hit the Endo right so come back to our uh create notes dialogue here so basically let us do a let us have a cons handle submit here so this handle submit uh is going to have a a type of uh it's going to have a type of e this e will be a uh react. form event right it's going to be HTML form event so it's going to give us a type annotation uh for what this event is so the first thing here we going to do is we'll just do e. prevent default so we don't want to submit the actual form right so then we're going to come down here to this form component here and just do onsubmit so we're just passing the handle submit function here okay that's pretty pretty cool and then let's actually continue coding out so what we want to actually had hit the end point to actually create this remember this create notebook endpoint so let's create a mutation for that so cons uh create notesbook uh equals to uh use mutation so this use mutation a mutation is basically like a a function that hits an end point okay so this mutation will take in a mutation function which is going to be Asing function uh and we need one more package to actually hit the end point we'll just mpm install AOS so AOS is uh just a HTTP client to actually help us hit the end point at the back end so we'll just do uh cons response cons response equals to await exos poost sorry exos so when you import exos uh let's import exos from ex so ex. post so we'll be hitting the end point right so be SL API SL create uh sorry slash API slash create notebook so make sure that this matches whatever you have here right create notebook right so is uh mapping to the file this create notebook file folder I mean okay and then we'll just return response do data okay so remember we also need this like uh remember when we hit this end point we are expecting a name in the body request body so you have to pass in this name into the request body so this name will just be the input field so this input is basically what we pass in we write in this text box here so now we got this create notebook function this mutation we can actually call it so before we call it let's actually check if input equals to uh empty string let us just do uh window. alert say please enter a name for your notes for your notesbook and then we just return okay so if the input is not now then I actually do create note. mutate so create this create note uh book function has a mutate uh function on it where we can just pass in the variables so in this case we don't have any variables that need to pass in here so pass in undefined but then the second variable is an object that will give us some callbacks so on success so if it succeeds we're going to just do console.log yay uh notes created then if it fails on error we'll just uh just do console do error error so we just log out the error so let's save it first and let's actually try it out right now so I'm going to do here is basically when I just when I by write when I enter something like a cat and press create it's going to call this handle submit function it's going to B then going to call this mutate function this mutate is whatever is here this mutation function so it's going to hit this endpoint create notebook it's going to pass in the input as a name it can return response or data and remember if you remember just now we are just trying to lock the image description to make sure the open AI is working so let me just open up the terminal here so that we can see the image description being locked out if everything works correctly so I'm going to just press create and then we can see that it's compiling the create notebook route and then if everything works perfectly okay perfect see now we can see that this image description so this is the response from open AI is it will say that oh minimalistic and flx flat start thumbnail description playful feline with cous eyes right uh yeah so we can see this description is what we this image description we can fit this description into the D API right so let's create continue creating the backend all right so come back to your open a file right so now that we have this let's actually make the generate image so this image will have the obviously the prompt right so this promt comes from this uh the function up here this image description so we have image description which is a string and let actually call the open a function so we'll do a TR catch block so we'll do cons response equals to await open a DOT uh uh create image passing in the prompt is the prompt being the image description we passing Nal one so how many image you want to generate we want to generate one image only and will tell you the size of the image you want to generate is 256 by 256 pixels yeah 256 by 256 so yeah like this and then lastly we can just do cons data equals to await response. Json so want to convert this response into a Json format then we can access the image we can get cons image URL equals to data. data at index zero right. URL and then lastly we can just return image URL as a string then if there's any error let's just console. error the error so let's save it and by right this function will give us back a image URL pertaining to the image description generated by open itself so come back to your root. TS so after we have generated the image description all right so let's actually now tra generate the the image so we're going to first check if not image uh so if not image description right that mean something R wrong so I'm going to just return a new next response response saying that uh fil to generate image description as in in a status of 500 all right then if so if there's image description let's actually generate the image so we do count image URL equals to await generate image here so we get it from the open AI uh passing the image description so now this image URL will hopefully return us with the image URL that's generated then we'll check if not image URL that means something R wrong so I'm going to copy this here and we'll just say that failed to generate image let's save it all right then Lastly lastly let's actually create the new notes okay so uh con notes equals to await DB so we're going to try to insert a new note within the table create a new row so this DB remember we import it from at lip DB so this is the if you come back to your lip DB file this drizz RM this DB is what we accessing so you can call AWA DB do inserts into the dollar sign notes which is from the schema dot uh values so want to insert insert the name so if you press control space you're able to see the different attributes that we need to pass in to create the rle so the name will obviously be uh the name that comes from this request body so we can just short-and it and then for the user ID right we get it from this user ID up here and then lastly we need the image URL which is from this image URL from this open AI here okay effect and then we want to return the new inserted node ID right so like which what's the new create newly created ID so we can do returning uh what what do we want to return you want to return the inserted ID to be uh dollar sign notes. ID and then finally we can access it by doing here we can just do notes IDs right and then we can just return a next response uh return a next response Json passing in the want to want to return the new ID that's has been created right so just do notes IDs at index zero. insert. ID so because this uh insert statement is going to return us with an array of with a list of all the inserted statements but because we only inserted one so we going access the first one and we access this inserted ID which comes from this returning statement here so then finally this no ID will give us back to the inserted newly inserted uh row row ID okay so that's pretty much it so let's save it and let's actually try it out so come back to your create note dialogue so we can see that it's on success right if we succeed right we know that it's going to return us with this object with this attribute called note ID so let's actually destructure this notes ID and then we can just console.log a notes ID so I can say that uh created new note okay so let's actually try out so I'm going to open up the console here and save it so we going to hit the end point right it's going to hit the endpoint then it's going to call the it's going to call the image URL it's going to generate the image and then you going to create a new R the database and return us with the note ID which will then console. log out here if it succeeds so let's actually try that so press create so right now it's hitting the end point although you can't see it so you can see that it's trying to hit the end point so let's wait for 8 to 10 seconds and hopefully y hopefully it will create a new row and console to lock out the newly created ID all right so perfect it works so here in the console you can see that it says created new note with this object of note ID so let's actually inspect this note okay so come down here so let's come down to the new Prisma not Prisma Studio sorry the drizzle Studio we do MPX drizzle kit Studio let's inspect the note that we have created here okay here so you can see that there's a new note with ID of one that name is Cat created now and have a new image URL so this new image URL is the open AI dly image so let me copy this and let me just inspect it on the URL so we can see okay so that is a cute very very nice minimalistic cat image that's been generated for our notebook so now that we know that it works so that's really really good okay so let's close this down and uh now we can move on so let me just close this visual studio and exit it out all right perfect perfect perfect so if it successfully generated it we going to then redirect them to a new page uh we got directly redirect them to like the uh to this page for the uh note ID for them to actually edit their new notebook okay so here we're going to redirect them to this page so here on success let's actually redirect them so we'll just get the router so cons router equals to use router so this use router comes from not NEX router but from sorry import from Nex SL navigation here is use router okay so invoke this and we get the router object so if it succeeds right we can just do router. push slote book slash note ID like this okay perfect yeah then that's pretty much it yes yes yes okay so then if there's an error let me just uh do window. alert uh fil to create a new notebook okay so let me actually try it out let me just try it out so uh one more thing to add is when we come down to this button when it's loading when it's creating we actually want to disable the button right for a nicer user experience so for this button we'll just do disable so we disabled it when the create notebook is is loading so this create notebook has a attribute called is loading to tell whatever the request is still loading and then we'll have a loader so if create notebook do is loading right so if it's loading let's display a loader so we'll have Loader 2 from lucd D react we'll give you a class name of with of four height of four margin R of two and animate spin so let's save it so let's actually create a new notebook now so click on here and let us create a a doc notebook so when I press create you can see this is loading to indicate that's a that is actually doing the API call and then if everything works it's going to Jetpack the note ID and it will redirect us to uh sorry it's going to redirect us to this/ notebook note ID that we got back from the new uh created Ro so let wait for a while and then if everything goes well and yep that's perfect so now we can see that it redirects us to/ notebook SL2 so this is the ID yeah okay so that is excellent that's excellent we have created a new notebook we can create a new r and we have generated the image for the thumbnail okay so now that we have redirected this notebook page let's actually start working on the notebook page okay so come on to your app directory let's create a new uh folder called notebook right cuz this is trying to correspond to notebook right and then inside the notebook folder let's create another folder called angle brackets notes ID right and then within this folder let's create a page. TSX so this uh angle brackets is a wild card it's a wild card to access this like uh ID variable here so let's do TS r f c right to get the react uh react component and just let's do notebook page all right so we got the notebook page how do we actually get the notes ID from the URL though so uh next J actually provides us with the with the note ID in the props itself so within the props you can access the perms object within the perms do have a note ID which is a which is a string so this note ID is going to correspond to like whatever you have put in the angle brackets not not angle brackets square brackets so then we can destructure the perms and we can destructure the note ID within the perms so for now actually just display the note ID to make sure that everything is working so in this case yeah it's showing the two the two is showing which represents the notebook SL2 here okay so now that we got the no ID let's actually retrieve it right so I'm going to make this into a server component so we can fetch it directly in the component so this component is going to run once in the server it's going to fetch the database for the ID and going to return the HTML to the client so let's do let's actually check if the users authenticated here first so cons user ID equals to awaits off so this off comes from cler nextjs and then now we can just do um let's do cons notes equals to await uh sorry await U DB so the database from dzo do select from the dollar sign notes where equals right with can just put it in the sense right so actually there'll be an end Clause right so end so there'll be two Clause the first is the notes the dollar sign. notes. ID has to equal to par in notes ID and the uh dollar sign notes. user ID should equals to the user ID here so this will be this will be also yeah so let's see the reason why because this not user ID might not exist so if not user ID right so if it's unauthentic unauthenticated let's just return um uh return redirect from next SL navigator to slash dashboard so let's save it so basically what we did here is we get the user ID right if there's no user that means they're not loog in we got to kick them back to the dashboard right if they are if they're in we're going to try to get all their notes right so the note will be where the ID the note ID equals to the PM's note ID the URL perm well and also the user the user ID of that note must match the user ID that's lock in CU we don't want uh other people to view your notes right so we have this end clause and then this notes will have just check we're going to check if not notes do length equals to one so basically if if notes length not equals to one that means if there's not exactly one note that means uh we didn't find the proper note then we going to just do return re direct to/ dashbo so if we have found a note we are ensure that the note will leave in notes index zero all right so now they got this note and I can actually display it by doing just putting in here so let just do like this this on the stringify notes now and two and now we can see that here it shows we able to see the ID the name the Creator at image okay so that's good that's good so now let's actually build out the UI for the for this note page here so instead of returning the Json let us actually just return a diff this diff will have a class name of mean height of screen greeny ping of eight Y and then here we'll have another diff with a class name of Max width of 4 XL and margin X of AO within this uh second diff we have a link here this link comes from next SL link here let's actually just link it back to/ dashboard all right uh yeah so actually I'm sorry above this link wrapping this link that's actually another diff that wraps this link so this diff is going to be what is going to be wrapping like this back button my name and the delete button here okay so obviously because you want to put it in a row let's actually give it a flex right so let's actually not do that first let's do bother Shadow XL border Dash Stone DH 200 rounded large padding of four flx and items sorry flex and items of Center so this is rounded here so let me save that first and now we can see that it shows up here okay that's good so then this link here let's actually show the button to go back so we have a button that says uh back so like give you a class name of uh BG green 600 and a a variance of small SM yeah so this is size of small okay so now we got this back button here all right that is perfect that's perfect uh one more thing Let me see what is the issue here uh okay yeah let me just refresh the page here okay so beside this a button beside this link right I also have the link let us have the the user's name right we have to display the name and basically which notebook they on so to get the name of the user we need one more package which is the uh mpm install uh at cl/ backend so this cl/ backend will give us some backend utilities to get the user from the actual user ID okay so let me just uh get the CL user right so come back come down to your lip folder and let's create a f f just called click server. TS so this only runs on the server right so this click Das server. CS will import from at cl/ backend we import the actual CL object and we can just is just one line export a new cons CL CLI it goes to cler right passing in the API key uh sorry so for this API key we pass in process. env. C API key so if you come back Tov file we can see there's this CL secret key so copy this secret key and actually paste it here so we are trying to access this secret key so just save it and now we got this clck instance that we can use so come back to the page. TSX here we can actually get the cons user equals to cler uh sorry cons user equals to cler so this cler comes from our cler server do users. get user passing in the user ID so then this will contain like uh all the stuff like uh this will awaited so we get back like the first name and the last name all right so let us actually put it in the the UI itself okay so uh underneath here this uh this link underneath this link let's actually have another spacer that just put w-3 so it's just a width of three just a empty diff and we have a span this span will have a class name of font semi board and then inside this bam will have user. first name and then user. last name so if we save it here we can see that my name shows up here right so it's my first name combined with my last name here okay that's good so then lastly for this underneath here let us have a uh span and we have a class name of inline block with margin X of one and we just have a slash and after this ban after this ban we have another span that have a class name of text- stone- 500 font semi B and here we'll put the notes. name okay so now we can see there's a nice flash slash here followed by the name of the notes so this is uh this combination of these three spans here okay all right so then basically after this pen we'll have a delete button here okay so we'll do the delete button uh later on but just know that uh the delete button will go here so let me just put uh ml AO and we'll put a delete button to do here so we can see that we put a margin left of Auto so that this gets pushed all the way to the left to the right side here so later implement this this delete button okay that's good then finally finally finally underneath uh this underneath this diff so underneath the we can collapse the Border here here and then we'll just do underne so above the two closing diff we have a another diff of height four so it's a empty spacer diff a spacer diff of height D4 and then underneath here is where we're going to put our editor so here is going to where our editor goes so this editor is going to be this thing that you see here that has all the functionalities built in so that's the main part of the application so for now I'm going to build a a container around it right so I have a diff here and this diff is going to wrap this editor later on let's give you a class name of Border Stone of 200 Shadow XL uh border rounded large padding X of 16 padding uh y of eight and then lastly width of four so let's save it and right now here is where our editor will go yeah so you're doing great so now the next part is going to be actually configuring the editor and I'll show you how to actually build out this very customized editor from scratch okay so now let's actually begin building the editor component which is the main BL of this project so be using a editor uh Library called tip tab editor so it's a it basically giv you a lot of functionality for building a very customized and full fles editor application so let me walk you through how you do that so so come down to your app and let's actually under our components let's create a new component and let's just call it Tip Tap editor. TSX so let's do tsrf c okay so we need a few dependencies for this tip tab so the first thing we need is um M install sorry at tip t/ react then we need tip t/ PM so this is PM stand for proos mirror so proos mirror is a primitive which tipt is built on so we need that for certain apis and functionalities and last thing we need tip t/ uh stter starter kit so this starter kit will give us a certain default configuration for like text or like paragraph or headings for us to start playing around with so we need these three things so we'll wait for the mkm install to be finished all right so uh my mistake here here it should be tip tab not tip tab so make sure you spell it right so then we going wait for the mpm to install Okay so once it install let's come to this editor the first thing is let's actually make it into a client component because of using state so uh I'm going to just configure the editor so what we going to do is here is we need something called use editor so let's import the use use editor Hook from the tip tab so import from at tip t/ react and we will need the a use editor okay so let's come down here and let's actually initialize the editor so we'll take the cons editor equals to use editor we're passing several things so the first thing is autofocus to be true so whenever the page loads we want it to automatically focus on the text box so it's a good user experience and then we'll have a extensions so these extensions are the remember the starter kit we install so we need the starter kit so let's import uh starter starter kit from at tip t/ starter kit yeah that we're passing the starter kit into the uh extensions array and then uh lastly we have a Content so this is a is a what is actual content that's going to be displayed in the editor so we'll bind it to a state called uh editor State and we'll do set editor State equals to be a it's going to be a string okay so then the content here is going to just be the editor State all right so then uh lastly on update so whenever whenever we change the like we make a change in the editor right we're going to just call this function it's going to do set editor state to be editor. get HTML so we can see there's a lot of APs I get Json and things like that right so you can read all of this in the documentation I spent about a few hours reading to the documentation so just dist it down to the most essential things that if you're interested in exploring further and expanding on this editor then of course you can read the document ation but anyways this editor basically allow allows us to use this method to get back the HTML which will then bind it to the state this internal local state okay then lastly for the the UI let's actually return a a diff this diff is going to have a uh have a in another diff call just for the editor content so this editor content we can import from tip t/ react and we just have to pass in the editor to be the editor instance that we have instantiated inst here so let's save it and let's actually import the tip tab editor here so let's just do tip tab editor and let's see if it works so I'm going to just refresh the page and let's see if everything works okay and it's good it's working so now we got this editor and we can like it's a multi-line thing yeah so you can see that tiip tab actually comes with like a very it's quite basic for now right but I'm going to teach you how to customize it so I guess the first step here is actually to uh remove this outline border cuz it looks very very annoying doesn't look nice so if you inspect in here we can see that there's this uh this class name that's wrapping everything called the uh tip tab proos mirror class so we're going to Target the class in our CSS file and remove the outline for now so come down to your global. CSS scroll all the way down here and we going to add a custom stying to the tip tab uh tip tab do Pros mirror Pros mirror class so we're just going to remove the outline that's all that need to do and if you come back here right now we can see that uh there's no longer a outline here and it looks much cleaner in my in this case all right so that's good that's good so let's actually continue uh defining it so uh let's see what I want to add here so let me now teach you how to add this like a det bar so like you see if you scroll up here like this and you press Bol uh if you press Bol you can actually bold it yeah so I'm not sure why you can bold it in this case b yeah you can see that if I press uh command B it BS it or I can command you to like underline it and stuff like that so I'm going to teach you how to get make this editor work all right so uh come down to here let's actually create a new menu bar so this menu bar will be a separate component that's going to leave on top of the editor so uh come down to your components actually create a tip uh Tap menu bar TSX we do TSR fce okay so for this menu bar we will need to accept the editor so remember this editor that we have defined uh in the tip T editor here so this editor we need to pass into this uh menu bar later on so let's actually just import the uh menu bar into the editor first so I'm going to come up here and just for this outo diff let's give you a class name of a flex uh yes a flex and then underneath here let us just do a uh sorry actually this should be a react fragment I'm sorry uh cuz I was thinking of something else uh let's move this react fragment down and then move this diff content down here so I'm going to explain what this is so this Flex is going to contain uh the you see this menu bar is one component and this save button is another component so we have the tip T editor menu bar as well as a button uh that says saved okay so then it's going to be then uh it's going to line up side by side and then inside this edited content here we add more content down here so it's just minus stying thing so we're going to pass in the editor right it's going to pass in the editor from here so I want to make sure this editor exist first so we'll do if editor exists then I'll put the T the menu bar here so let's actually configure the props to get it in so let me just uh put the tip tab here so in the props we expect the editor to be a editor from tip t/ react then now we can uh destructure it from here okay so now the menu bar is showing up here and we can continue on okay perfect so for the menu bar I'm going to just do uh let's see uh I'm going to return a diff right this diff is going to have a class name of flex Flex D rep and gap of two so this diff is just basically contain all of these buttons so all these buttons are differently sty like uh it's a custom buttons like each button like uh an individual button so then we got to just wrap it into all this Flex con a flex container so let me just demonstrate some uh some let me demonstrate something about the how I say the tip T menu bar so we have a just a normal button here so this is not from Shen because we want to style it a certain way first so for this button let's have a uh Bol so we import this Bol uh icon from Lucy D react let's give you a class name of width of six and height of six so let's save it and right now we can see that this is both icon here as a button okay so uh so so so so so for this button we'll pass in a few things so on click right so let me explain how this works so we're going to do editor. chain so this chain is basically saying that the editor we can chain a lot of commands on it so the first thing here we want to do is we want to focus back on the editor so after we focus on the editor we want to toggle both so we can toggle whatever selection we have it on right now so imagine I have this selected here and I press this B button it's going to focus on the editor and they toggle toggle board on the selection here okay so after toggle uh toggling the bo we can actually run the command here so I just basically found this API from their documentation I'm just briefly explaining it here to you so just need to know about how it works like this and then for here we want to disable this button right we will disable it when edit when the not editor do can. chin. Focus tole sorry tole run sorry here do uh run okay so what it does is we want to disable it if the editor cannot toggle B so in some cases like it just doesn't it's not able to tole it B then we just want to disable this button here so you can see that this is command this this can uh can function here okay and then we'll have a class name of we got to check Okay so if editor sorry we're going to check uh for a condition so if editor dot is active so if it's already bought right we want to show an active class right so we're going to show a is active right otherwise we're going to show empty class name okay so right now we can actually see in acity so if you come down to this thing it's right now it's invisible so I can type a few things and I I highlight this right highlight this button I press on this button and we can see that it's B up right so why does is is it just change the thing it focus on the editor and it toggles the B so right now we can we have like this b b functionality working at it so all we need now to do is we have to fill in the rest of these functionalities for like the iism and the hings and stuff like that so let me just run through it uh really quickly I'll run through the first field then I'm going to copy in the rest so that we can have better understanding okay so underneath this button let's actually do the do the next part so we have another button so you know actually I can just copy this button down here and right instead of tole both this to tole italics italic and then here will be toggle italic here and then here be instead of checking for B we want to check for italic here italic all right then for this instead of this B icon I'm going to just put it as italic icon italic icon from Lu DH react so if we save it right now we can see that there's not italic thing so if we highlight this and we can italicize it yeah so the rest of the concept is going to be very very similar so what I'm going to do is instead of wasting your time and just doing the same thing over and over again I'm going to just copy in this uh copy in the code here from my code up here and let me just clean up a few things and explain what I've just did so Tip Tap menu okay so basically it was the same thing right I'm receiving the editor right then I'm basically returning the buttons that buttons like the Bol buttons and things like that right except that I just went through the documentation I found everything that is available to us so we have this itze button we got this strike true button for the toggle strike toggle code so we can like toggle it whether we want to make it a code block or not okay then we have Hing so the all the Hing level one to five to six so can have like a different hings but right now let me show you why it's not working because even though I toggled the hings right we can see the text but the text size stays the same even though right even though it's H3 right let me show you if I toggle it H1 H2 H3 right the thing is being toggled is being changed but the Tex SI is not changing this is a Tailwind issue so we actually need to install a Tailwind a Pros utility so this tailn typography allows us to uh give back the markdown the in terms of like the H1 it will allow ta to respect our H1 H2 H3 sizing so to install this let's actually install the typography extension right so come down to your terminal and just do mpm install at TN CSS typography and then underneath here come back to your TN config file okay and we we need to add this typography into our plugin so scroll all the way down here for this plugin we add one more thing called the the require which is the typography library that we just install this extension so after we have this we can come down to our uh tip tab editor right remember this div that's wrapping it let give you a class name of of Pros so now this Pros will allow us to like uh respect the H1 and H2S so if we save the pros now and we wrap it now we can see that now it respects the H1 H2 H3 H4 and H6 yeah so that is basically what the pros of ta win utility does for us yes so coming back here so it's just a different heading levels things like that then we have obviously the bullet list for the like you want to make a list of something you can do that here you can have order list code blocks block Cotes and and undo and redo basically so this supports undo like I can press contrl Z to undo yeah so I hope you understand this it's quite simple API once you understand how to use it then all this list order is show basically icons that I found from Lucid D react so yeah there's not much nothing too complicated about it yeah so one more thing here is right right now we can see that when we when we click on it when we click on the button right it when though it's active if is active we don't have a way of showing whether it's active so come down to your global. CSS file okay we can do do is active right we give a background color of let's say # da d a DA and have a border radius of two pixel so if we save it right now we should able to see it in action right we can see that when we B it right there's a background to it I tell the size we can see there's a nice background to integrate which which modes are uh which modes are basically active here so this H4 H3 H5 yeah so that's pretty much very simple styling so these all uh read from the documentation so you don't have to worry about me too much if you're interested you can always read more into into it yeah so I'm just here to like save you some time and show you the basics of how to actually get started with this a powerful editor uh Library okay so now that we have uh the editor up and working so now let's actually work on uh doing the saving functionality so the auto save so um every time you type right so we're going to have a debounce so after the debounce we're going to basically save it to a database so if you're not sure what debounce is I'm going to show you in a while so don't worry about it so I guess the first step here is actually let's close off the menu bar and let's come up here and let's actually have a u react. use effect and let's actually just toggo it on every time the editor State changes okay so let's just do console.log editor state okay so let us actually see what the editor is going to look like so every time I I click on it we can see that the paragraph is form and if I have a heading right we can see there's a h one and the paragraph right so let me just move myself out the way so we can see how the how the editor looks like so basically want to save this piece of information to the database and then every time we look into our notes uh this note page we're going to just uh so that we can load it in and display whatever we have in the database okay so to do that so let's actually do the debounce so the thing is the reason why we want to debounce it is basically imagine we are typing in every time right so we can see that I'm typing in like let's say uh a few tens of tens of like let's I'm typing in like maybe 20 or like 30 characters per second okay 20 or 30 characters per second like let's say I'm typing fast right we do not want to basically hit the database endpoint and and try to save the save the whole text every time we type a character it's going to be very wasteful of resources right it's also going to be very like uh slow right cuz you're hitting the database like imagine 20 times a second that's not very optimal so what debouncing is is debounce is basically it will just uh wait for a while after you have finished typing then you wait for maybe like 500 millisecs to make sure you have finished typing then it will trigger the save right so that's what debounce means so to Rite the debounce function let's actually come down to lip and let's write a use debounce hook. TS okay so it's a custom hook for us to implement the debound functionality okay so I'm going to just import uh react from react we're going to be using use State and let's export a function called uh use debounce okay so this debounce is going to take in two things going take in the value which is going to be a string and the delay which is a number so this value is basically what is we passing the editor State and this delay is basically how many milliseconds do we want to wait after I finish typing to trigger the save okay so the first thing we going to do is going to take cons uh debounce value and set debounce value it's going to be a state right passing the initial value here okay and then what I'm going to do is I'm going to have a react do do do use effect uh here and I'm going to just do con Handler equals to set time out okay and basically what want to do is set the bounce value to be the value every time time the value changes okay so I'm going to set a time out for let's say delay seconds delay seconds okay I'm going to put the delay in here also and then I'm going to return a uh clean up function to clear a timeout so let me explain what I'm going to do doing first after I call it out I'm going to return debound value debound value okay so what's happening here is okay let's see this value right it changes every 20 characters per second right it changes 20 times per second what it's going to do is every time it changes right it's going to call this it's going to call this use effect is going to be called okay so when it calls it's going to try to set the debounce value to the change value right but it's going to change it it's going to only set it after let's say 500 milliseconds right but if I change it again within 500 milliseconds it's going to call this function a cleanup function to clear the timeout so it never actually gets set so basically what what it happens is only if I stop typing after 500 milliseconds then does this debounce value this function gets C and then my debounce value will be set so let me show you in actions to have to show you then it's going to be much easier to understand so here I'm going to have a uh cons debound State uh debounce at deter State equal to use debounce we can pass in the editor State and pass in a uh delay off let's say 300 seconds would that be enough actually let's just do 500 milliseconds 500 milliseconds so now I'm going to try to conso to lock out the debounce editor state every time it changes okay so let's try it again right so now let's I type look as I type you see nothing gets locked out but watch as I if I stop typing and after 500 milliseconds see it gets locked out so I can keep typing and if I stop for 500 milliseconds it gets CAU it gets caught again so that's what the debounce this so we can basically like type and then we can type and only if you stop typing then will the function be called and then we can call we can call the save function here so here we can then save to D B okay so I hope you understand the debound thing so now let's actually write the function the API end point to actually uh do the saving so come down to your uh folder and let's under our API let's create a new folder called save not within this folder let's do a root. TS and let's do export a Asing function called post and the request will be a standard request object okay here all right and then here we can actually do the uh function to actually save the note so the first thing here is let me just wrap it in a try catch block and we'll just destructure we'll get the body out of AIT request. Json so get the request body so uh within the request body I will need two things right we will need uh the sorry we need the sorry let me see we need the notes ID and the editor state so this editor state will be what is shown here this uh debounce console loock and then this note ID is basically we are trying to see which note which note are we actually trying to update okay so we need to this we need T this so we need these two pieces of information so we got to just check if not editor state or not note ID so if neither of these are if one of these are not passed in we want to return a new new uh new next GS new sorry next response right passing in uh Missing edit State on no ID in a state of 400 okay so if there's there's a note ID we'll just set the uh note ID equals to pass in notes ID so let's actually change this to a let so that we can reassign it here okay awesome so now let's actually get the notes right so cons notes we're going to try to find the note with that note ID so we do await DB dot select from dollar sign notes from the schema sorry here from notes dollar sign from the schema right where right where uh the notes. ID equals to the note ID pass in from the request body so if notes do length not equals to one so if that means there's not exactly one note that means something went wrong so let's just return a new next response saying that uh failed to update passing the status of 500 okay so now that we got the note let actually get the note equals to notes index zero so it's the first notes out of this array okay then now let's actually check okay so uh let's just do uh if notes but editor State not equals to editor state so this is the Old State right this is whatever is in the database and this is the new state so we can check if is different because if it's the same then it doesn't make sense updating it we're just wasting resources so only if it's different then let's actually set set right so let's just do await db. update uh update notes we want to set the editor state to be the new editor state that we got up here right where uh where the note ID equals to the note ID pass in from the body yeah so I hope you understand it's just we're just updating the editor State based on the Note ID and then if everything goes well let's return a next response do uh Json saying that success equals to true and a status of 200 if there's any errors let's actually console do out console. error the error and let's return a new next responsejson right asking the success success to be false and the status of sorry St sorry this is response let passing a status of 500 internal server error okay so now we got this Point Let's actually try using it on the front end so remember you want to save to DB every time the debounce editor State changes right so let's actually do that so first let's actually get the mutation function so cons save notes equals to use mutation from uh 10 St query passing the mutation function to be an async function to hit the end point so we want to hit this a safe not end point here so let's just do cons response equals to await exos host SL API saave note so this is what is uh What uh end point we have just written here then we need to pass in two things right we need to pass in the notes ID which is uh the notes so how do we actually get access to this note we can actually get it from the notes uh you can get it from the notes which is a notes type so remember this note type we got it from our our schema here right so we can actually get this notes type here and can destructure the notes and let actually passing the note ID to be note ID and then of course we want to have the editor state to be whatever we have this editor State here so this note ID and this editor state will be passed back into this function no ID and editor State and then we do the corresponding update so we actually need to pass in this notes right if not we do have access to this notes so come down to your uh notes ID page for this tip tip tab editor TP script is yelling at us because we need the notes we need to pass in this notes object that we've got fetch from the database so now we have this we got access to the note we can have access to the note ID and stuff like that then let's just return response. data okay pretty cool pretty cool so now we got this function to actually update the update the database so let me just do if we could just check if the bounce editor State equals to an empty string let's just return course it doesn't make sense if you want to like uh update an empty string so if not let's actually just save note mutate so call the mutate function which will in turn call this uh in hit this end point okay so we'll do mutate uh passing in undefined so course we're not passing in anything to this like to this function here right and then on the second argument here we can just do on success so if there's a success let's actually console. loock success update and let's passing Thea then uh on error so if there's an error that's console do error error and let's just do yeah that's pretty much it okay so then let's actually have a saving State also so right now we can see there's this save button so we can see that in a deploy app when it save is a save disable save and then as we like type around we can see that it changes to a saving state so we can actually do that here by creating a new local state so let's have another state called cons is saving and we do set is saving uh actually we don't need a local state we can just use this save note function so underneath this button here right so this button here we can actually put uh here so we do uh save notes dot is loading so if it's Saving right I'm going to do saving if not I'm just put saved and that's actually this able this button and give you a variant of outline so right now it will be safe and then basically when I hit end point so let's actually try out okay so I'm going to open the console I'm going to start typing so it's going to hit the endpoint right then you can see that it it flash for a second and it successfully updated that means our database has been updated and we written with a success of true so that's good so now we can see that as we type and stuff it will hit the end point and it will save it I can bold it if I bold it it will also trigger the save so let me just remove this console lock cuz it's getting kind of annoying so let me just remove this and yeah everything is working perfectly so we're a to save it so let me just right now if I refresh the page right we can see that uh if I refresh the page right now nothing appears right so we need to load in the the Save Editor State on initial render so what we can do here is come down here to this remember here this we have this uh editor State instead of setting to MD string we going set it to the note. editor State yeah and then yeah so if there's no editor State we can just set it to empty string yeah so in the case that uh en state is now right we'll set it empty string if not you can see that it's showing up here so I can like type like Hello World right so we can see that it's saved if I refresh the page right it saved to the database okay that's perfect so uh we have learned how to use a debounce hook to debounce our change and then once the debounce has been triggered we I've taught you how to actually hit the endpoint to save the editor state within the database so you're doing amazing then the next St we're going to teach you how to integrate the the AI into the chat completion all right so just one thing I want to change is if there's no editor state that means like it's a new Fresh notebook right so instead of putting MD string I'm going to put a h one that that basically has the notes notes name in it so that it's like a better user experience so I'm just going Toc capsulate the notes. name and just put in the H1 tag all right so this a very simple UI fix all right so let's actually now start working on the AI completion part so in here in the original app you can see that when I press on let's say control I press shift a right when I press shift a it activates the AI and then it will just uh help me aut to complete all this stuff right uh and to do that we actually need to bind a custom key bind like a custom keyboard shortcut so that when we press shift a it's able to detect that we want to start Auto completing so to actually do the custom custom keyboard we actually need to create a new custom text so right now we can see there this u in the use editor we got this extensions on this start kit right so we're going to add another custom extension uh and this custom extension will contain the keyboard shortcut so to get that we need to import one thing from up here which which is uh import from uh let me see where is it from okay at tip tab tip tab SL extens text extension extension SL text uh all right and we need import the sorry uh the text so just default import so we can pass this text into the extensions here right but we want we want to customize it a little so let's actually do this we're going to do a cons custom text okay custom text equals to text do extend so we're going to extend this text I want to pass in the add keyboard shortcuts okay this add keyboard shortcut will be a function and what it returns is a it will return a a keyboard sh cut and then a function that will be CAU whenever the keyboard shortcut is uh triggered so in this case you want to be CAU whenever we have a shift a so when we press shift a we can to call this function and I'm going to do is just going just return true for now I'm going to say control. l activate EI okay and passing this custom text into the extensions list custom text and that's save it so now let's see if it works so I'm going to come open up this editor and the console so by right if I press shift a right I press shift a we can see that uh let's see if it works okay uh shift- a let's see if it works press shift a ah okay it works now so you see activate AI is being called so when we press shift a we can see that the activate AI function is being call so that's good so now here we know that within this function is where we can call the auto complete right so for the AI part we could be using a a versel AI SDK so it's a pretty new uh um package from versel right that give us a very nice library to interact with backend LMS and also give us that very nice a streaming effect so you see when we press like shift a right here there like the text will slowly come in one by one so we have to do that using the streaming effect so verel SDK give us that opportunity so let's actually set up the back end first for the completion so come down to your / API come down to your app folder come down to your API folder let's create a folder called complete with this completion let's do root. TS so this root. TS will map to a/ API completion so this file here will map to this uh will map to this URL so let's export a async uh function called host which will get in the request which a request object so let's actually import install the E from Vel so is mpm install AI so just two characters AI this will give us a lot of power in the completion so I'm going to close this down and we're going to import a few things from uh verel so the first thing is let's import the uh import from open EI H so it's the same configuration we did just now so we need the open EI API as well as the configuration object and now we want to import uh a few things import from AI so this AI is what is what we just installed so uh let's actually in uh initialize the opening a first so let's do config to new configuration passing in the API key to be process. env. open AI API key which is what we have from the EnV file here okay and then let's actually initialize the cons open AI equals to new open a API passing in the configuration object so now we can actually play around with this openi object so the first thing here is actually let's uh extract the prompt from the body so to that we'll do cons uh prompt equals to await sorry await request of Json so later on what we going to do is when we press shift a here we can to take the latest like May 30 characters and we can to pass into this prom here prom object from variable here so now we can actually request for the response right so we do cons response it goes to open away open ai. create chat completion we'll see the model will be uh gbd d3.5 dturbo for the messages right so we're going to have the first message being the system message to promp the system what his R is supposed to be so we'll tell it that hey uh you are a helpful AI actually I'm just going to copy in and just going to uh just tell you what is because it's quite a long prompt okay so here let me just copy here can I just copy this content all right so let's see here okay so I basically tell you that you're an helpful AI EMB bettered in a notion text editor app that's used to autocomplete sentences so the trait of AI include expert knowledge helpfulness cleverness and articulateness is a well behaved and well-mannered individual and it's always friendly kind and inspiring and is eager to provide Vivid and thoughtful responses so we're just basically prompting the AI on what we expect for the responses to be like so after that we can create another message and this time will be the the user to the user right so the content of the user will be uh let me just copy this in so leave all this in a paste bin down below so you can just copy from there so you have to like type it out manually so for the user will be saying I'm writing a piece of text in the notion text editor app help me complete my train of thought here and we pass in the promt so this promt comes from this request body and then we want to keep the tone of the text consistent with the rest of the text and keep the response short and sweet so this is some prompt engineer ing to make sure that the W output is uh is good and last want to pass in the stream stream passing the stream to true so this stream will then basically allow the open a API to pass in like tokens like one by one instead of like waiting for the entire response to finish before passing us back so better user experience and lastly we want to do cons stream equals to open eii Stream So this open AI stream comes from this AI library right and we'll pass in the response okay and then we'll do return a new streaming text response from o from AI so so this streaming text response function passing in the Stream uh stream okay so this will basically return us with a a streaming uh streaming content type that we can injust in the front end to basically uh mimic the streaming response when we press shift a all right so that's go we have finished the backend end point it's pretty simple po just Heating and some prom engineering so let's close this down so come back to our tip tab editor okay uh we can have a we're going to use a new a hook from we going to import this hook so let me show you what Hook is from SL from AI SL react so under the react library from from AI has a used completion hook so this used completion hook will allow us to interact with the backend API that we have just written is able to return us with the streaming tokens as we like uh manual trigger the AI completion so the first thing here what I'm going to do is I'm going to just take a cons equals to use completion I'll passing the API to be/ API completion completion okay so this API is the roots to whatever whatever back end here and it has to return a it has to return a uh streaming text response so this is ma to the root that we just done for this comp completion here okay because it Maps to/ API completion so it has to match here so we're telling you what API root it is and we can destructure a few things we can destructure the complete and the completion so this complete is a function that we call to trigger the completion to basically trigger the end point and this completion is a bunch of is just like a a react state to get back all the tokens okay so what I'm going to do here is a uh underneath here underneath here uh because here we know that we want to activate the eii right I'm going to Do complete so I'm going to call the complete uh function and pass in the prom so this promt is basically uh let's get the last 30 characters so let's do uh take the last 30 words so we'll just do cons prompt equals to this. editor do uh get text so this will get all the pl text do splits do slice uh sorry dot uh sorry split on the empty empty space right space and slice it by 30-3 and we just join it back with a empty space so let me just console lock out the prom so we see what is happening here so whenever press shift a we should get the latest 30 words right so let me just show you so let me like type in a bunch of stuff if I press shift a we can see that it gets back this uh this of 30 30 words right okay so now we to fit this 30 words into the completion uh end point so that's called complete on the promt itself okay and what I'm going to do here is I'm going to show you the I'm going to use effect use effect to basically uh console lock out the completion so remember here it also returns us with this completion variable so I'm going to show you what it looks like console completion I'm going to save it so for now I'm going to delete everything else and let's just type some something serious like let's say uh I like cats okay I'm going to press shift a it's going to trigger the thing and watch what happen soon right yeah so you can see this completion is coming back do you see this yeah so you can see that cats with their charming and things like that so this is the the completion variable so the issue you can see is that every time this completion it just like streams in token by token right so into then into the world then becomes into the world com uh full stop so how do we actually get that individual word so because right we want to get the individual word uh get in the vual word so that we can insert into the editor right the issue right now is because I have this function let me show you here so I'm going to do uh editor dot commands do uh insert content I can insert the completion right but I'm going to show you the issue here so let me just do editor so uh if not editor return so let's actually move this down below the editor so let me show you the issue right now so basically every time the completion changes I'm going to insert this new completion into whatever text editor I have here so let me show you the issue right now okay so I like head okay Watch What Happens press shift a and look it's going to give us a bunch of JB look at this this is not right this is not right why because every time this completion changes this completion is a whole another paragraph So if you keep like basically uh if you keep inserting content it's going to insert like all this junk paragraph because it's duplicated the completion is duplicated right we can see that uh uh here is duplicated it comes like token by token so we actually want to get the individual token that comes back from the completion and to do that we can actually have a we can save we can use a clever trick we can just do uh cons last completion equals to react. use ref passing empty string okay so then what we can do is here we can have a react cons uh token equals to react. use memo so this used memo is a is to memorize the function to memorize the calculation right so every time the completion comes back in we're going to do uh uh we're going to basically take the difference between the completion and the last completion so let us do uh let us actually get the memo let me just check okay so so if not completion we're going to return but then if there's a completion we got to just do cons div equals to completion slice so we get the whole paragraph and then just want to like uh take the difference between the whole paragraph and the last completion so that we can get the individual token that was actually returned from the back end so we'll slice by the uh pre uh last completion do currents do length Okay and then we can just return the diff so this will return us with the individual tokens and I can prove it by instead of this completion let me just delete this I'll put in token and let me just put in this token and actually console. loock token so if it's not not token we return okay so let me prove to you why this will work right now so let me just save it here again so if I delete the whole thing again I WR I like cat and this time if I press shift a we can see the tokens start coming back in see it's in addition right yeah so right now it's still uh it's still not working and the reason why is because let me show you uh if not completion right because after we have set the after we have set the diff we will still need to set the last completion current to be completion so after we have already take the difference we want to set the last completion so that it finishes the loop and then we can uh get the latest token again so let me try again so I like cats okay so let me open up the console here okay so I was debugging something but um I'm actually not really sure why it doesn't work or why it works but anyways we were talking about how we're trying to get back the individual tokens from the uh completion string right so what we did was we did a react use effect so whenever the completion came back we basically keep track of a last completion which is a ref right so this ref will not change will not rerender the whole component whatever it changes so it's very good to like just keep track of what the last completion was so uh every time this completion changes we got to basically take the last comp completion and we got to take the difference between the last completion and the completion so then we got to get back the individual individual token so this diff represent the individual token and then uh we can just set the last completion to be the current completion and we just take the editor and we insert the diff the token into the editor so right now it can't it works right now so I can just do like um cats and docks R right so if I zoom in I can press shift a and it should just give me back a nice a streaming effect where it just automat adds it into the text editor and it saves it automatically yeah so we refresh it and it saves yeah so that's how the completion Works uh yes yes yes so I hope you understand that part so it's just about manipulating and using the use completion Hook from versal Ai and then trying to get the difference and to get the actual individual token to then insert the individual tokens into the editor y okay so we have completed U pretty much the bo of the application we get to like edit it with b and like things like that and we also did like the auto complete by pressing shift a so let me just the last step here is just to help me uh add like the the UI change for this like a tip press shift a for the auto compete so let's add that part in here okay so uh come down to this uh inside the under the editor content here right so we got remember we got this Pros right uh for this proos actually let's add one more class name for it let us add this pr-sm uh with full and margin top of four then underne this diff let have a height of four so it's a spacer diff empty div and here we can add a keyboard uh command so we'll give it a span of text SM and then let's give it a tip press uh so let's give you a kbd so it's a special keyboard element in HTML shift plus a and let's give it a styling so class name of padding X of two padding y of 1 padding y of 1.5 uh Tex super small XS font of semi bolt Tex gray of 900 sorry tax of 800 um BG gray of 100 border border Dash gray of 200 and rounded Dash large and then underneath here shift a let's do for AI auto complete so if we save that right now here we got this so let me add one more spacing some spacing in front of it here so like this and then here we can also add a spacing like this okay so now it looks good so we got command to like tell people what to do to actually uh do the auto complete so that's perfect that's perfect okay so uh now that we have finished it let's actually go back to build our uh dashboard page so right now the the dashboard has only this new uh this notebook so now let's actually fetch all the notebooks and display in a grid layout here so I'm just going to come down and let me just close out all my tabs so we are more organized so come down here close my tabs and let's come back to our dashboard page okay so let's dis all the notes but first let's actually get all the notes okay so for the dashboard page what we need to do is uh since let's Mak it into a server component and then let's actually fetch it okay so let's do cons user ID equals to off right so make sure that uh the user is log in then we do cons notes equals to await db. select from dollar sign notes where uh where equals uh notes. user ID equals to user ID so add exclamation mark So that we ensure that the user will always be here so now we get back a list of all the notes that belongs to this user that is log in so now let's actually look through it right so below here inside this grid layout so remember here uh this conditionally render so let's actually do the thing so uh if no not display this so let's do uh notes. length equals to zero if so basically if there's no notes then it Mak sense to display this uh uh text string that we have no notes okay so if you have notes let's come down here so underneath the create note dialogue so let's do notes. map so for each note Let Us return a uh normal a tech so a normal anchor tag so we have H ref equals to SL notes slash not sorry slash notes uh notes. ID okay so let's give you a key of notes. ID all right within the the anchor tech let's actually add a uh diff so this diff will be the card so we have a overflow of hidden Flex Flex of column when it's when we hover over it let's have a shadow of XL transition when we when we hover over again we negative Translate Y of one so within the card here let us show an uh image so let me show an image first let me give you a width of 400 and a height of height of 200 and we'll give it out of notes. name and finally a source note. name and the source Pro will be notes. image URL all right so some it might be now so let us do empty string if it doesn't exist okay then underneath here let's actually save it first so now we are able to see okay we got the cat and the dog right let me let me let me show you why the image is not showing up first so let's come down below inside the diff below the image let's have another diff they have a class name of padding of four and then have a H3 so this H will have a class name of text XL font semi B text grade of 900 then within the H Tre let us put notes. name underneath the H Tre let's have a spacer of H1 height of one so it's empty diff and we'll finally have a paragraph tag that have a class name of text smm text Gray of 500 within the paragraph tag that us show new date notes. created at right dot to local date string okay let's save it and right now it should show up nicely okay the date does not exist so it's a capital D so let's save it and okay showing so now we got this uh date here and stuff so uh the reason why is not uh there's one more thing I'm missing let me see what I'm missing okay overflow things like that okay so uh one more thing for this diff on this overflow hidden let's just add round rounded large so that is a little more rounded okay so it shows up nicely here and if you go back to like refer back to our thing uh let's hope that it looks similar okay perfect so there's actually another a border around it so let's actually add a border so we'll do uh border border stone stone of 200 okay so it looks nicer now perfect perfect yeah okay so uh the issue right now is why is the image is not showing up is let actually go inspect into our uh our drizzle kit I'm going to show you what is the issue so we just do MPX drizzle kit Studio to open up your database client in the website all right so open this up okay look at this image URL I'm going to copy this image URL I'm going to paste it in the URL right is going to tell us that he has he has expired so the the reason is because open AI open AI uh D open AI d uh to expiry right so uh by default d 2 gives you about I think two hour after an hour so the URL that's generated like this URL is only valid for an hour so after an hour this URL will no longer be valid so it's actually up to us the developers to save this temporary URL to another uh per perent storage in this case this permanent storage I'll be using Firebase so to actually uh store this let's actually go to Firebase console so search for the Firebase console and you have to log in or register for an account so Firebase is like a is a back end as a service to give you that uh give you a lot of functionalities like authentication and storage so once you log into the dashboard come down to add a project so create a new project and for the project let's call it uh uh ideation D YouTube then press continue and uh we don't to enable Google analytics just press create project and it's going to wait for it to create the project okay so now that the project is ready let's press continue okay so we'll be brought to the uh ideation YouTube plan uh to the dashboard in this case we want to uh activate the storage right so come down to the sidebar and you should be able to find let's see if I'm able to activate it if I zoom out a little okay uh come down to the the sidebar and I want to search for the storage so storage here so retrieve user generated content so here is where we going to store our our images P the the jpex so let's press get started in the storage and start in test mode so that um we able to access it so then press on next and then lastly it's saying that this is where our default go storage bucket is set so let's choose a location that's near us so in this case I will choose uh Asia South is one so CH somewh that's closer to you okay and then after done let me actually then just come and press done on the bottom right corner my head is blocking but yeah so we are creating a bucket meaning that we are choosing a location nearest to us to store all our uh D images so we're going wait for you to create the default bucket and then I'm I'm going to teach you how to actually set up the Firebase to connect to the storage okay so when the bucket has finished in initializing we have to create a new web project so uh is a create a new website that can is able to consume these images so come down to the project and just press web right so we're going to create a new web app so you can name it whatever you want I'm going to create just name it my web app and we don't want to we just disable Firebase hosting and I'll Press Register App and it should be able to give us uh all API keys to connect from our web application onto this Firebase okay so let's follow it so we need to install this Firebase package so it's okay so let's come down to our terminal and let's just stop the dzo studio and do mpm install Firebase all right so once we have installed Firebase let's see what is next uh sorry uh what happened to our thing one app my web app okay so after we have installed Firebase right we need to copy this uh code into our Firebase uhts so come down here and close the terminal come down to our uh lip so under our library we got to create a new file called Firebase TTS and we'll basically just copy in whatever code is here so press copy and just copy here so I'm going to you have to blank out your uh API key here okay blank out your API key so what you going to do is going to copy whatever you have here cut it out and go into your EnV and let us do uh actually let me see yes we have to do Firebase API key and just paste it in here okay then with this you can then come back here and just do process. env. Firebase API key cuz we do not want to upload this into our like how say we don't want to upload this into our G repository for everyone to see all right so after you have this you can then close the Firebase tab all right so the next step for the Firebase is want to initialize the storage right so uh underneath here we'll do export cons storage equals to get storage so this get storage will come from uh Firebase storage so import get storage from Firebase SL storage so get storage and passing the app instance here so this storage is what we will be using to interact and upload all our files onto um a 5way storage basically so let's save that okay so let us now talk about the flow so right now if you come back to your uh create a uh create notebook rout create notebook rout here right we can see that uh we're returning this note ID and then after we have created it so we create note dialogue right remember that after we have um created this new note we are directly navigating to this notebook so before we navigate it right we actually want to hit another endpoint hit another endpoint to upload the temporary uh di URL to permanent uh fire base URL okay so let's set up the endpoint to upload the image the temporary D image to the permanent permanent Firebase uh storage so come down to your app directory come down to your API folder and then let's do upload to Firebase let's create roots. TS within this Firebase okay and now let's actually work on this okay so uh let me see if I can find it all right so let me just export a async function called post which will take in the request object and let's actually do the uh try catch so we're going to accept a a note ID from the request. Json await request. Json uh Asing function export Asing function await request. Json so we'll be expecting a notes ID from this so what we going to do is after we we have uh got created a new node here right we're going to basically hit this Endo hit the end point passing in the node ID then from this note ID we uh will then extract out the extract out the DI image URL then save it to Firebase okay so hope you understand that part so let's get the image URL so we'll just do cons note equals to await DB do select from dollar sign noes where equals uh so you want to equal to the par in uh sorry the do sign notes. ID and the par in notes ID okay so this will be notes so then we're going to check if not notes uh notes index zero. image URL so if the D to uh image URL doesn't exist that means something went wrong so let's return a new uh next next response saying that no image URL passing in a status of 400 okay now we will try to uh upload the file to Firebase so let's actually create a new uh how say underneath the come down to your fire base. TS right write a function below here to actually upload the file okay okay so uh so we're going to write a function export e sync function right which will uh which will be called upload file to Firebase so it's going to take in the image URL which is a string and a prompt which is also a string so this prom is just to name the file just to give the file a name so let me just name it as name here okay so the first step is actually let's do a try catch block so we'll try to get the response equals await fetch so this is the native fetch URL a fetch API and we fetch the image URL so this image URL remember this is the D 2 AP the D 2 temporary temporary image URL okay so we await it and then we'll get the the buffer equals to await uh response. array buffer so this will convert the uh image into array buffer and now we can just do uh cons file name equals to name. replace want to replace all uh uh space characters with just an empty string and we'll just add uh uh dates do now plus jpeg so we're just renaming the file to add a custom ID and then make sure it's a JPEG format now we can do cons storage ref so we want to get the reference in the Firebase storage equals to ref so this ref is from the Firebase storage we pass in the storage object from this uh get storage here right and then we pass in the uh file name okay so then after we got the storage ref so now we got a reference to that actual file we can then upload the image to that file so we do await upload bytes so this upload BYT is also from Firebase storage we pass in the which reference we want to upload to we pass in the buffer okay so this buffer contains the actual image right and then uh we want to finally tell it that the content type is a image/ JPEG cuz we're trying to upload a JPEG image up to the storage okay and then finally at the end we can just do cons Firebase URL it goes to await gets download URL from Firebase storage passing in the storage ref so these are all just uh I read documentation and figure it out myself right so I'm just stealing it down for you in this simple code snippet telling you how to get the image URL and uploading it to Firebase in the end we just want to return the Firebase URL so we're going this is the permanent Ur URL now and then if there's an error any error let's just console.log console. error out the error okay so now we got this function actually call it so come down to your create not uh come down to your uh uh upload to Firebase route again and this time we're going to then call um let me see so after we got the image URL let us do cons Firebase URL equals to await upload a file to Firebase pass in passing in the notes notes. image URL okay and then we pass in the name here okay so does this make sense so because this upload file to Firebase remember it takes the image DRL and the name so you're just passing in the D URL and the the name of it so it's going to basically take the d URL it's going to put it into Firebase storage and return us with this Firebase URL so then finally we want to save this Firebase URL to the permanent database okay so let us do await db. update dollar sign notes do set uh image URL to be the filebase URL and then where equals notes. ID equals to pass in node ID so we're just updating the image URL to the the permanent Firebase URL when the note ID equals to the passin node ID from the body and then lastly we can just return a new next response of true and the status of 200 then if there's any error uh sorry okay okay and if there's any error we just return a uh error and a internal server error code okay perfect so now we've got this uh endpoint that's actually call it so come back to your uh come back to your how say create uh create note dialogue right got this create notebook mutation let's create another mutation for the uploading of the Firebase so we do uh let us actually get the Firebase root so let me just do this uh cons upload to fire base this is going to be use mutation the mutation function this time will be async right cons response response equals to await exos post SL API SL upload to Firebase right and passing in the notes ID so let me just delete this okay so this API SL upload to Firebase this is the roots that we created just now right this this roote this uh upload to filebase root right so remember it needs two things right it needs no sorry it needs one thing we need a note ID so the note ID will be uh how do we actually get the note ID we can get it from the props itself right so let's get the note so uh so to get the note ID we can get it from the parameters parameter so we can just pass in the notes ID okay and then we can just return response. data so let me just walk you through what we're doing first I'll write out the code then I'll explain so after we have uh created a new note let's actually also do upload to Firebase mutate uh passing in the note ID so after we have created the note right we got the note ID the newly created Noe ID then we got to call this upload to filebase mutate passing this Noe ID this no ID will then be propagated up here to this new ID this mutation function and you going to be hitting this upload filebase API with this new ID ID and then we going to just take the temporary D API and then convert it into the Firebase URL and then we can just return response. data and just save it so then it's going to basically convert our di image into the Firebase uh storage so let's actually try out so I'm going to refresh the page and let's see if it actually works okay so I'm going to just uh create a new notebook and this time I'm going to call it let's say uh type script and let's create so let's look into the cont cons for any errors so it's going to basically start creating the notebook so the first create notebook route is going to handle uh the creation of the images uh the D image and then here we can see that there's an error right it says that uh this encoding library is not found so we actually need to install this encoding library for it to work so just do mpm install encoding okay and lastly let's go back here and let's see if it still won't work for now course we need to try again actually it works so we can see that this uh URL is now uploaded to the Firebase storage so you come down to the resz studio right so let's do MPX drizzle kit studio right so if we refresh this we can now see the typescript has a Firebase URL so this Firebase storage this Firebase URL is permanent for else this is temporarily okay so everything works fine everything is perfect everything is working good so the last thing here is uh instead of using this um instead of using the default image we're going to use the next next uh SL image so import this next SL image component so it will help us optimize our image further if you save it right now it's going to throw an error right because let me show you why it's going to say that this uh host name is not configured so we actually need to add this a Firebase storage host name to our configuration so let me just copy this uh this Firebase storage. uh Firebase storage. googleapis.com let's copy this this and let me just come down to my next config.js so inside this config I need to basically allow and white list this image a domain so we do images right passing in the domains to be an array and it's going to basically allow any images from the Firebase storage so let's save it and let's actually delete the previous two records so I'm going to choose these two records and delete it delete and now I'm going to refresh the the I'm going to refresh the server so do mpm so right now it's it stopped right so let's do refresh sorry let us see if we able to get it up and running again and now it works okay so now we're using the the we're using the how to say we're using the next SL image component and let's actually try it again so let's create a new notebook and this time let's call it uh something creative like let's say computer Graphics let's see what kind of Graphics is able to generate so you hit the API it will generate the D to image and then you will redirect us to the uh notes note page right and then you will then in the meantime in the background you will upload that di API into our Firebase storage so we can see that configur Graphics is Right written here I can press shift a and it's able to generate uh the auto complete for us so that's beautiful everything is working perfectly okay then it's automatically it to the database and then when we press back it then we can refresh the page and it's able to see the computer graphics and this image is then uploaded into Firebase so yeah I think that's it for the for everything actually one more thing is so right now if you press like if you press here it brings you to SL notes which is incorrect so it should bring you to SL notebook instead so let me come down here to this so instead of leading to sln notes SL notes book so let's save it and let's try again so if I press this then it correctly brings me to the typescript page all right that's perfect that's perfect and last but not least let's actually do the delete button okay it's a pretty simple component so come down to your components let us do components create a delete button. TSX so TS r f c okay so for the delete button let us you try to accept the notes ID right which is a number so let us destructure the note ID so this is will tell uh our database which note to delete so then we're going to do uh let us actually render the button so return a button that have uh variance of destructive so it's red color and then we'll here have a trash icon so this trash is from Luc react and then basically let us give it a size of small and then onclick so when we click on it let us actually confirm to the user first so cons confirm equals to window. confirm are you are you sure you want to delete this notes question mark So if not confirm we want to return so they're trying to delete the operation but if they confirm it that means we actually want to call the API function so let let us create a new endpoint in apepi let's create a folder called delete noes and let's create a root. TS so it's the same thing let us do export async function post taking the request to be request and now let's actually get the cons notes ID equals to await request. Json so we get the no ID from the request body and then we can do await DB do delete uh delete from so delete uh notes where equals uh dollar sign notes. ID equals to par in notes ID okay so then we got to just return new next response of sorry new next response of uh okay and passing a status of 200 okay so yeah it's just a simple function to take in the Noe ID and just return it so let me just save it and come back to the button and we can then take the mutation so let's actually convert this into a client component first and we can just take the mutation function so cons delete noes equals to news mutation passing in the mutate function to be async we are going to hit and point right so we do cons response equals to A W exos post post slash API SL sorry SL API SL delete notes right so this is the rout that we created just now right passing in the notes id id right which we receive from props and then we just want to return response. data okay so then if confirm we going do delete uh notes. mutate we could passing undefined because it's not accepting any parameters and then on success we just going to just uh do we going basically route them back to the dashboard so let's get the router so we just do cons router equals to use router from make sure it's from next SL navigation not next router okay and then we're going to do uh router. push dashboard yeah then if there are any errors on error we're just going to console. error error so let's save it and then let's actually import this delete button so come down to your uh notes ID uh to your note page so remember where we put our where do we put our delete button here okay so let's just import the delete button so do delete button right need to pass in the notes ID which will be notes. ID so now let's save it and now have a delete button showing up here so if you press delete you ask us for the confirmation then let's actually add one more thing so we want to disable the button when the delete notes dot is loading so while it's loading we want to disable the button so let's try again so it's going to ask me to confirm when I press okay it's going to try to delete and it will just come back and we can see the note has been deleted so yeah everything works perfectly and yeah I think that's good yeah everything looks exactly the same and I'm pretty happy with what we have completed so far so I think if I'm not wrong that's everything everything you need to know uh about the application all right so um I'm glad I'm very happy that you did this with me it's a very quick and simple build this time not very long but it showcase a lot of the power of artificial intelligence and the open a API so the last step here is I'm going to teach you how to deploy to uh versel right it's going to be very simple so the first step here is come down to github.com New we going to basically push this repository to a new GitHub repo all right so uh I can do is I'm going to expand the screen move the screen here so the repository name you can name it whever you want and going just put ideation D YouTube and you can put it as public or private up to you and just press create repository so after you have created repository you have to follow the the commands here so come back to your vs code come back to your terminal I'm going to stop everything running okay stop everything running here uh yes and then I'm going to do git status to make sure that everything here is added so let's do git at all then get commit D am initial commit so we commit our all changes now we can do git Branch DM so to rename our Branch to main if you have not done so already and then we can add the origin right so basically linking our local repo to the remote repo and lastly we can just run git push d u origin mean to then push our code up to the the the repo so now let if we refresh the page we can see that all changes is up here so that's perfect okay so now let's actually deploy it so there's one more there I think there's uh two more things I to do so come down to your uh create a note rout create notebook root right so to make this into a run on H the H run time right remember the benefits of H runtime it allows your function to run longer and faster so you have to export a runtime export cons run runtime equals to H so if you export this runtime variable uh next year versel will detect it automatically and you will deploy this function on the H runtime instead of the normal nodejs run time okay and one more thing is come down to your uh next config.js and just add the typescript flag right to ignore during ignore the build errors and for the es link to ignore uh during builds to be true so yeah this just for the versal deployment then after that you can just commit it again so I'm going to use the graphic user interface so I'm just going to move H function so just commit it and push it out so this is the last two things I think yeah so if you come back back up here we can refresh and we're able to see our changes uh hopefully let's refresh one more time and yeah so we can see that our fun our comits being done now Edge comit Edge function so to deploy versel is really simple come down to ver.com and come back to the dashboard and add a new project so add new project project and choose your uh report that you have just linked up so just press import and can just name it whatever you want here and then choose the build setting so for the not sorry build the environmental variables so come down to your EnV here so a neat trick for you is press command a or control a if you're on Windows to select everything and then copy it come back to verel and can just paste it in here it's able to copy and detect all your enval variables in here with that you can just press deploy and then everything should be well and in a few minutes uh it should be building and just Deploy on that easily so I'll see you when it's finished building okay so wait one more thing I want to do is uh come back to your come back to your dashboard here come back into your application come on to your settings and for the functions right I want you to choose one that is nearest to you in this case I CH live in Singapore so I'm going to choose Singapore and save it all right so this is just to make sure that the the function the apis uh will be very near you so that the user experience be very fast yeah so that's pretty much it so come back to your deployments and we're just waiting for it to build yeah so I'll see you on the other side okay so it has been deployed successfully so now let us just visit the domain that have he has given us so let's actually try out and see and hope that it works so we can see that yeah not taking assistant or typ is working so let's press get started and it should promise to log in so just log in with your uh account and hopefully it will bring us to the dashboard where we're able to see all notes that we have done okay uh and then we can see the images will show up soon right let's try creating a new notebook let's create cats let's create and hopefully hopefully the age run time will work and does not time out on me okay so it works it works okay that's amazing so we can see that it brings us to the new notebook and we can type whatever you want here like uh press shift a and we can see the AI Auto completion still works perfectly it's deployed up here and yeah we can see that uh it automatically saves it right wait for it to save I can itze it and do everything like that and yeah I think that that looks perfect and if you come back to the homepage and refresh we can see that the DI 2 API should have generated image for us yeah and it's a cute little kidden pause things like that yeah so I'm glad that you are here with this journey so today we learned a lot so let me just recap what we have learned so we learn about next 13 how to style it properly with SH CN how to use the open AI with the di uh generator verel AG runtime I told you how to use drizzo RM to interact with neon DB how to use Firebase storage to actually store your files uh and also the tip tab uh Editor to actually give you the power to create the notion like editor and the versel AI is a ke for all the streaming AI large language model need so um I'm happy that you stay with me so if you enjoy and learn something from the video please like comment and subscribe I put in a lot of effort for this kind of videos and I hope you'll really learn something new and with that thank you for so much for watching and have a good day
Info
Channel: freeCodeCamp.org
Views: 60,125
Rating: undefined out of 5
Keywords:
Id: qDunJ0wVIec
Channel Id: undefined
Length: 176min 58sec (10618 seconds)
Published: Wed Oct 11 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.