Now let's go ahead and let's create the functionality so that when we click on a little plus button inside of this sidebar here, we open up a model to create our organization. And then we're also going to create a list so users can choose between all the organizations they have and quickly switch between one another. So the first thing I want to do is I want to go back inside of my clerk dashboard right here. So pick your application and go ahead inside of the organizations here on the side and in here you're going to have a prompt that organizations have not been enabled for this application. So go ahead and click enable organizations, and that's going to redirect you to organization settings and just go ahead and tick this little box right here.
There we go. And you can leave this exactly as it is. And now what I want you to do is go inside of JVT templates where you have the convex template. And in here you now have access to stuff like organization ID, organization role, and organization name and much more other stuff. So what I'm going to do is I'm going to go to the end and add a comma here.
And I'm going to add organization role. And then what you can do is simply find the organization role here and click it like this. And there we go. You can see that now I no longer have any errors if I for example forget the comma you can see that it has an error so just make sure that you have a little comma here and besides the organization role let's also add the organization ID and you can either write it manually or you can click org.id right here. There we go.
So just make sure that you don't have any errors, make sure that you don't have trailing commas. So remove that as well. Perfect. So I just added the organization role and the organization ID which is going to be very useful for us so we know which organization the user belongs to and also their role inside of the organization if you want to do even more granular control and just click apply changes right here and there we go if everything was successful you're going to get this template successfully updated and you should now see the organization ID here and the organization role right here. Perfect.
So now let's go ahead and what I want to do now is add a new component from chat CN which is going to be called a dialogue component. So let's go ahead quickly inside of our terminal here. Also for this part you don't need to have NPX convex dev running because we're not gonna do any back-end for now. So I'm just gonna do NPX chat-cnui at latest add a dialog which is gonna add a new dialog component and besides that I also want to install a tooltip component so when we actually hover on buttons here I want to show a little instruction on what the button is going to do so let's add chats in your latest add tooltip as well So we are adding a dialogue component and a tool tip component. And once those two have been installed, you can go ahead and run npm run dev.
And every time that you shut down your app and then run npm run dev, just make sure that you refresh your page. Otherwise your hot reload is not gonna work until you refresh. Great. So now let's go ahead inside of our sidebar component. So I'm gonna close everything here.
Oh yeah, we do need npx convex dev, my apologies. Otherwise our authentication is not gonna work so let's go ahead and open a new terminal and run npx convex dev like that and let's just wait convex functions are ready and now let's refresh. There we go. Now we can work. And let's go ahead inside of the app folder, inside of components, sidebar.
And inside of here, we are not gonna render side, instead we're gonna render a new button component, which currently does not exist. So inside of sidebar, create a new file, new-button.tsx. And inside of here, I'm gonna mark this as use client. I'm going to go ahead and import plus from Lucid React, just plus, not plus circle, my apologies. I'm going to import create organization from clerk next JS.
And then I'm going to go ahead and import from components UI dialog, which we've just added a dialog, a dialog content, and a dialog trigger. So we have something to open it. Great. And now let's just export const new button here. And inside of here I'm gonna go ahead and return a dialog.
Let me just indent this properly. And I'm gonna go ahead and give this a dialogue trigger, which we'll have as child prop. And inside of here, I'm gonna add a div with a class name of aspect dash square. And inside, I'm going to render a button, which is going to render our plus icon with a class name of text white, like that. And let me just indent this a bit.
And now that we have this skeleton set up, we can go back to the sidebar and import the new button so we can actually see this button that we are developing. So even in mobile, you should see a little plus icon here now which currently isn't doing anything. So what I want to do now is style the button so it looks a bit better. So let's give this button a class name of bg-white-25 so it will automatically give it a bit of an opacity on the white color. Let's give it a full height and full width which is going to be the maximum of this aspect square ratio which it is wrapped in.
And then let's give it a rounded off medium. Let's give it flex, items center, justify center, like that. There we go. So now it already looks a lot better. And now what I want to do is give it a default opacity of 60, but when we hover on it, let's give it an opacity of 100 and let's make that smooth by adding a transition as well.
And there we go, you can see that now when I hover on it, it pops up like this. Perfect. Now we have to add a dialogue content outside of the dialogue trigger here and very simply render the create organization like this. And now if you try and click here, you should be seeing this create organization right here, but it looks a little bit weird. It looks like there are two divs, like two white backgrounds here.
So we can resolve that quite easily just by modifying our dialog content a bit so let's give it a class name of padding 0 bg transparent let's also give it a border none and let's give it a max width of 480 pixels like this, there we go so if I collapse this this is how it looks like perfect so we are now ready to create our first organization excellent and this is how this class name looks so max width 480 pixels border none transparent and padding of zero perfect so before I create my new organization the first thing I want to do is create a list of organizations so we can actually see them being rendered here. If you want to you can already create one you're going to see it in the clerk dashboard but you're not going to see it here so I just want to wait before we do that. So inside of sidebar I'm going to go ahead and create a component called list.tsx. This list is gonna iterate over all of our current organizations and then render them. So let's mark this as use client.
Let's import use organization list from clerk next JS. Let's go ahead. And well for now, let's export const list by itself. And in here before we return anything, let's get the user memberships. From use organization list And let's define user memberships to be infinite like that.
And then I'm gonna write, if there are no user memberships.length, sorry, .data.length, we're just gonna return null. And inside of here, I'm gonna open an unordered list and give it a class name of space y4. And inside of here, I'm gonna go over usermemberships.data.map and let's go ahead and get the individual membership. And inside of here, I'm just gonna render a paragraph. And let's render the name, membership.organization.name.
And let's give this a key of membership.organization.id. Like that. There we go. And now I want to go ahead where we render the new button and above it. I want to render my list from dot slash list.
So we have a list and new button. Great. So now, if I go ahead and create a new organization here, I'm going to call this test and click create an organization. And I'm not going to invite anyone, so I can just press skip here. And let me just close this and see if this has worked or not.
And there we go. You can see how now we have test right here rendered. And let's just confirm on our clerk dashboard that it is also true. So in your organizations right here, you should see the new one. There we go.
Created today, one member and it's called test. So if I go ahead and create another one let's call this two and click create an organization I'm going to skip the invites like that Let's go ahead and there we go. One, two, and in here when I refresh, there we go, perfect. And now what I wanna do is I wanna display them in a better way and I also want to indicate which organization is currently selected, which one is currently active. So for that, we're gonna have to create a new component called item so on the same level as the sidebar index and list let's create a new one called item dot TSX which is going to be used client as well.
And in here, let's import image from next slash image. And let's go ahead and import from at clerk next JS, use organization. And let's add use organization list. And let's also import CN from libutils. We already have this.
We got that when we installed a chat CN UI. So in the root of your application, you have the lib folder and utils inside with the CN package, which we are gonna use to dynamically style our Tailwind elements. Now let's create an interface item props and let's give it an ID of string. Let's give it a name of string and image URL of string as well. And let's export const item.
And inside of here, we can destructure the name and image URL and ID. And let's just assign those props here. So those are the item props. And then in here, I'm going to return a div with a class name of AspectSquare. So the same I did with my button, so everything is consistent.
And let's give it a relative class name. And then I'm going to render an image component. And I'm going to give it a source of image URL. I'm going to give it an onClick of an empty arrow function for now. I'm gonna give it an alt of name.
So let's order that like that. And I'm also gonna give it a property of fill and for the class name I'm gonna go ahead and write the following so I'm gonna make it dynamic by opening CN and for now I'm just gonna give it some default classes which are gonna be a rounded MD cursor pointer opacity 75 hover opacity 100 and transition So the way the CN library works is that in the first argument or any argument, you pass in just the default classes, which you would pass it like you normally would in a class name. And then later we can do dynamic stuff. Like if something is true, we're going to do the opacity, you know, 100, for example, stuff like that. But we don't have anything to compare it with because we need to add some hooks here.
So let's do the following. Let's go ahead and let's get the current organization from use organization. And let's go ahead and let's add set active to come from use organization list. And now let's check if this item is the active organization. So if is act, so sorry, we are gonna define is active So we are going to define is active to be the current organization, which we get from this hook, question mark dot ID is equal to the ID which we are passing right here.
And then let's do const on click here. If we are passing the ID, which is the current organization, which we get from this book, question mark dot ID is equal to the ID, which we are passing right here. And then let's do const on click here. If we are not at, sorry, if there is no set active, we're just gonna break the function. So you can just actually return like that because it's possible that this set active is undefined, right?
So no even point in calling this action, if it's not undefined, if it's not defined, sorry. Otherwise we're gonna set active and we're very simply gonna pass in the active organization to be the current ID of this item like that. And then we can replace this empty on click to actually use the on click element. And we can add dynamic class name here. If is active, very simply, we're gonna add opacity 100.
There we go. So now let's go ahead back inside of our list here. And now we're gonna use that new item. So remove this paragraph here and instead use the item, which you can import from .slash item. So all of those are on the same level inside of app folder, dashboard, underscore components and our sidebar folder because all of those only relate to the sidebar.
And now we have to pass a couple of props here. So let's give it a key to be membership.organization.id. Let's repeat the exact same property, but for the ID prop, let's give it a name of membership.organization.name. And last one is gonna be image URL and the prop for that is gonna be image in URL and there we go. Now you're gonna get this error that the host name image.clerk.com is not configured inside of our next config.
So what we have to do is we have to go inside of our next.config.mjs right here and inside of here extend this object with images, remote patterns, protocol is going to be HTTPS and then host name is going to be whatever is written for you here so I believe it's gonna be exactly the same so for me you can see that it says that hostname image.clerk.com is not configured so that's the hostname that I have to add right here. Image.clerk.com. And once you save this, I would actually recommend that you shut down your app and restart it because in previous versions of Next, this was never nicely updated. So that's what I'm going to do. So in your terminal where you run npm run dev just do it again and if you want you can also restart npx convex dev but I don't think it's gonna do any difference so let's try this again so I'm just gonna go ahead and refresh my page Let's do it a couple of times just to ensure this is working and there we go.
You can now see my organizations right here. You can see how when I select on another one after a couple of seconds, that's the one that becomes with opacity 100. But we have two problems here. First one, there is no indicator what's the difference between these two. So one thing that we can do is we can use our tooltip component to add the name once we hover.
But it would be nice if we could somehow generate the initial of the name of the organization to indicate to the user which one is which. Well, a clerk can do that. So you can go inside of clerk right here and let's go inside of customization avatars right here. And in here you have the default user avatar if you want to change the color or anything but you also have the default organization logo and in here you can select the initials and there we go you can click apply changes and now all of your organizations are going to have initials instead of those boards if you want to you can actually remove these organizations and then create new ones, or they're gonna maybe be upgraded a bit later. Let's try this out with the name test.
So if I create a new organization, Sometimes it's not immediately reflected, but it definitely works because I use it in the initial project. There we go. So new ones now have this image. Yes, so you have to remove the old ones. You can do that by going inside of the organizations here and then remove the old ones.
Yes, and also I don't know why exactly when I finish creating an organization and when I click skip here it seems like nothing is happening. So we're going to debug that later but for now you can just manually close. Okay, so what I want to do now is I want to create a hint component so that when I hover over any of these elements I can see the full name of the organization and also when I hover on this I want a tooltip to tell me exactly what that button is going to do for me. So for that, we're going to go ahead and go inside of the components folder and create a new file called hint.tsx. And in here, I'm going to go ahead and import everything we need from at slash UI sorry components UI cool tip so we need the tooltip itself we need the tooltip content We need the tool tip provider.
We need the tool tip trigger like that. And let's export interface hint props here. So that's gonna take the label, which is a string. We're gonna have children which are react.reactNode. We're gonna have side which is gonna be an optional top, bottom, whoops, so top, bottom, left or right.
We're gonna have optional align, which is gonna be start, center or end. And we're gonna have side offset, which is gonna be an optional number and align offset, which is gonna be an optional number as well. And then let's go ahead and export const hint. And let's just destructure all of these props here. So I'm going to align hint props.
And then we can get the label. We can get the children, side, align, side offset, and align offset. Perfect. And now inside of here, I'm just going to return the tooltip provider. And let's make sure we close this tag.
Inside, I'm going to add a pull tip component itself with a delay duration, sorry, delay duration of 100, so it appears a bit faster than usually. And let's add a pull tip trigger component here, which is very simply going to wrap whatever we wrap it around. And let's use as child to ensure the styles are not broken and there are no hydration errors either. And then let's add tooltip content here. And inside of the tooltip content, we are very simply going to render a paragraph, which is going to render the label.
And inside of the paragraph, let's give it a class name of font, semi bold and capitalized. And let's give the tooltip content some props. So class name is gonna be text white, background black, and border black. And let's give this a side prop of side. Let's give it an align prop of align and also side offset of side offset and align offset of align offset there we go and now what we can do is we can reuse this hint component wherever we need to reuse it.
So the first place I want to do it is inside of the app folder components sidebar new button. So this button which is used to open the content. So I'm gonna go ahead and inside of the div where we have the aspect square, add a hint component from components hint and wrap the button around it. Whoops. Like that.
So you can import hint from components slash hint, which we've just created. And let's give it a label of create organization like that. And it says that hint cannot be used as a JSX component. Oh, I believe I forgot to write a return. So yes, my apologies.
Wrap this entire thing in a return. Of course, you can we cannot just write JSX plainly. All right, like that. There we go. No more errors.
And now if you try and hover over you can see that we have a label create organization the issue is is that it appears on the top that's not where I want it to appear. So what we're gonna do is we're gonna give it a side of right and then we're gonna give it an align of start and let's give it the side offset of 18. Like that. And there we go. Now it looks much better.
Perfect. And now I want to use that in the item component as well so that we can display the name of each of these organizations so let's go inside of sidebar item dot DSX let's go ahead and import hint from components hint and we're gonna go ahead and give it a name and we're gonna give it a name of item.dsx let's go ahead and import hint from components hint and we're gonna go ahead and wrap the image in the hint component like that And let's go ahead and give it a label of name. Let's give it a side right. Let's give it an align of start and side offset of 18. Like that, there we go.
So now if I go ahead, there we go. You can see exactly which organization I'm going to click here. Perfect. And you can see how the opacity changes once I click on a new organization. Perfect.
So we just did the entire functionality for our main sidebar right here. So what we have to do now is we have to build the organization sidebar right here, which is gonna allow you to change the settings of an individual organization and to also switch organizations in a different view. Great, great job!