
No Comments Yet
Be the first to share your thoughts and start the conversation.
Be the first to share your thoughts and start the conversation.
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
00:00:00Â So going back to the code, we can head over to root and then go to the page.
00:00:07Â We haven't seen it in a long time.
00:00:09Â It's finally the time to focus on that as well.
00:00:11Â So right here, we'll turn this div into a main tag.
00:00:16Â That's an HTML5 semantic main tag with a class name equal to home-container.
00:00:24Â Right within it, we'll render our component called header, which we have created not that long ago.
00:00:32Â And in this case, we'll pass it an additional class name equal to sticky left zero and top zero.
00:00:43Â That means that we have to get into the header and make it accept additional class names by adding the class name in the props.
00:00:50Â And then alongside the typical header classes, we want to render something known as CN, which stands for class name coming from libutils.
00:01:00Â We can wrap the header and then also render these additional class names when needed.
00:01:08Â Next, we can render a div within that header with a class name equal to flex, items-center, gap of two, and on large devices,
00:01:20Â a gap of four.
00:01:22Â Later on, we'll render a notification list right here.
00:01:26Â And here we can also show if signed in, we can show the user button.
00:01:32Â just so we can interact with our profile.
00:01:35Â Of course, both of these things are coming from Clark.
00:01:38Â So now if we go back, you can see a live docs, notification, and the user button.
00:01:43Â Next, we can go below this header and we can create a new div.
00:01:47Â This div will be different depending on how many documents we have.
00:01:52Â So let's say cons documents is equal to an empty array right now, which is truly the case.
00:01:58Â So let's remove it for a second and say if documents.length is greater than zero, then we want to display a div.
00:02:09Â else we want to display another div.
00:02:12Â For now, since we really have zero, we can focus on this second part where we'll give it a class name of document list empty.
00:02:24Â And here we can render an image.
00:02:28Â with a source equal to forward slash assets, forward slash icons, and forward slash doc.svg.
00:02:37Â Make sure to import the image from next image.
00:02:40Â Give it an alt tag equal to document with a width of about 40, height of about 40, and a class name of margin X of auto.
00:02:51Â If you go back, you can just see a document logo right here.
00:02:54Â Next, we have to add a button to create a document.
00:02:59Â And for that one, I'll create a new component just so we can nicely contain all the logic within it.
00:03:05Â I'll call it add-document-btn.tsx where we can run RAFCE and we can automatically import it right here below the image.
00:03:18Â add document btn, and to it, we need to pass two different things.
00:03:23Â We need to know who is the user that is creating this account.
00:03:27Â So to be able to know that, we can very easily get the access to that info with Clark by saying const Clark user is equal to await current user coming
00:03:41Â from Clark Next.js.
00:03:42Â And we have to make this page an async page.
00:03:46Â Next, if we don't have a clerk user, we can just redirect using the next navigation redirect to forward slash sign in because unauthenticated users cannot
00:03:58Â create documents.
00:03:59Â Now that we have that info, we can pass the prop of user ID equal to clerk user dot ID, as well as an email equal to clerk user dot email addresses,
00:04:12Â zero dot email address.
00:04:16Â That's a mouthful, but we wrote it.
00:04:19Â And we can now move into the add document BTN to accept these two props, the user ID and the email, which both are of a type add document BTN props.
00:04:33Â Within here, we can create that button.
00:04:35Â We already have created a Shazian component of button.
00:04:40Â So we can just import it from UI button and it can say something like p tag.
00:04:49Â class name is equal to hidden.
00:04:52Â And then in smaller and larger, we can actually make it block so we can see the text and we can say start a blank document.
00:05:00Â If we go back, you can see this button right here, but now let's style it a tiny bit.
00:05:05Â To this button, we can provide a type of submit because we want it to submit the form.
00:05:11Â And if we want it to submit something, we have to know what.
00:05:14Â So let's say on click.
00:05:16Â We want to run a function called addDocumentHandler.
00:05:21Â So let's define that function right at the top of the return by saying const addDocumentHandler is an async arrow function.
00:05:31Â I'll show you which logic to add here later on, but for now, let's add the class names to this button, such as gradient-blue,
00:05:40Â flex, gap of one.
00:05:45Â and a shadow of MD.
00:05:47Â Also, above the p tag, we can have an image, which we need to import from next image.
00:05:53Â That'll have a source equal to forward slash assets, forward slash icons, forward slash add.svg with an alt tag of add.
00:06:05Â a width of 24, and a height of 24 as well.
00:06:10Â And let's not forget to turn this into a client-side component.
00:06:13Â So right here at the top, I can say use client, and we need to do that because we're using buttons, we're clicking stuff.
00:06:20Â So if we go back, we can see a nice looking button right here.
00:06:24Â And since we don't have any documents, it's taking all the space, which is exactly what I want.
00:06:29Â So now what do we want the button to do once we click it?
00:06:33Â Well, let's open up a try and catch block.
00:06:36Â In the catch, we can simply console log the error.
00:06:39Â And in the try, it'll be pretty simple.
00:06:42Â We just want to call the createDocumentServerAction that we have created not that long ago.
00:06:49Â And to it, we can pass an object with a user ID and email.
00:06:55Â The output of that will be the actual room.
00:06:58Â So we can say const room is equal to await create document.
00:07:04Â Once we get the room and if we get it, so if room, then we want to use the router to push to that specific page.
00:07:12Â So let's declare the router above by saying const router is equal to use router coming from next navigation, not next router.
00:07:22Â And we can say router.push to a template string of forward slash documents, forward slash, and then dynamically room.id like this.
00:07:35Â Okay.
00:07:36Â What do you say?
00:07:37Â Let's give it a shot.
00:07:38Â I'll go back right here and click start a blank document.
00:07:44Â And if everything goes right, we should be redirected to a new documents page with a new specific ID.
00:07:52Â This means that everything went right.
00:07:55Â But why can't we see this new document that we've worked so hard to create?
00:07:59Â Let's go to the code and check it out.