Now it is time to build the schedule page where we will see all the interviews that we have.
Either that is completed, it is live, or it is upcoming.
Right?
And then when we click to this button, we should be able to see a model where we can give the details
and schedule an interview.
So we're going to give the title description who is the candidate and who are going to be the interviewers.
So this can be only one but this could be multiple.
So currently this user is selected.
And if this user wants to it can add more interviewers into the call.
Right.
So they can select this one and it would be listed here.
Then we'll select a date as well as a time.
And at the bottom there is a button to submit this or cancel it right.
Okay.
So with this in mind let's go ahead and try to build this UI.
So I'll visit VS code where we have this schedule page.
And I will first kill the left hand side and mark this with use client because we'll do some client
side stuff.
So we're going to get the router from use router hook from next navigation.
Then we'll say you would like to get the use user role hook.
So from here we can get two different values.
Is interviewer actually three different ones.
But we're going to get the loading state as well as this if user is interviewer or not.
So I will say if we are in the loading state we can return a not a p tag, but this loader component
that we have built.
And then if we are not in a river, so let's say if not is in a river.
In this case we can take the user to the homepage.
So I'll say router dot push to the homepage.
And I think previously we also used something like loading three dots in the homepage.
So instead of having this we can use this component loader UI.
It should be okay.
Now let's go back to the schedule page.
So now that we have protected this page we can return the actual UI.
So instead of putting everything here I will create a component I'll say inner view schedule UI.
So basically here we checked for the access if there if user can access this page or not.
If not we will take them to the home page.
But else they can see this component, this UI.
And this is something that will that will create under the source under the components.
So if you really wanted to you can put it put this component into the schedule page as well.
So this is this is what I'll be doing.
Actually, let's say dot TSX, this is the only com, this is the component that we'll be using only
in this page.
So that's why I'll go ahead and say Ahrefs save this and try to import it here on this file.
Okay.
So now let's try to build this component.
This is going to be a long one.
But we can go step by step.
So first I will get the stream video client.
So this is something that we have done multiple times at this point.
And we would like to get the current user by using this hook coming from Clark.
Then we would like to have this state to check if the dialog is open or not.
So it is going to be this dialog.
When we click to this button it would open and we can close it.
Okay.
Then we're going to have one loading state called is creating.
When we are creating the call.
When we are creating the inner view we will have a loading state for a second.
Then we can go ahead and get all the interviews to be able to display it in this page.
So I'll say inner views and I'll say use query coming from convex.
We'll say API dot inner views dot get all interviews.
Since we are the admin.
Since we are in the admin page, we can go ahead and actually fetch all of them, right?
This schedule page is only related to admins.
And then we'll click to get all the users.
So I'll just say const users use query.
Just like this.
We can go under the API under the users and get the users.
Then I would like to get a mutation which is to create an inner view.
So this is something that we have done previously right.
That was the mutation.
And you can see these are all the mutations and queries that we have created under the inner views.
And we would like to get the create interview mutation.
Then I would like to fetch all the candidates.
So let me just paste this in.
We will say const candidates.
And from the users we will basically filter out the ones that has the role of candidate.
And we can do the same thing for the inner keywords.
So this word is really hard to pronounce but I'm trying to do my best.
Then we would like to have some form data right.
This is some form data.
We need to keep it in this state.
And for this we will go ahead and create a use state where we will have this object.
So we have the title description the date we can update this time.
By default it's going to be 9 a.m..
And then we have the candidate ID as well as the inner keywords IDs.
Right.
So this could be multiple ones.
So we're going to hold it in an array.
And by default this is including the current user's ID.
Then we would like to have a function to be able to schedule the meeting.
So before we build this UI, let's handle all the functions and the states that we would need so that
we can build the UI pretty quickly and easily.
I'll just say, um, how do we type this schedule meeting async function where we'll do a bunch of different
things.
So first I will add my if cards.
I'll say if there is no client or if user is not authenticated, return out of this call.
Don't do anything.
And we'll say if form data doesn't include any candidate ID or interviewer IDs, then we can show a
toast and then return out of this function.
But else we can start to creating it right.
So we'll just set our state to be true.
Then we'll have a try catch and then maybe a finally block.
And in the finally block.
As you can imagine the loading alerting state will be equal to false.
And then in the try we can get the form data and destructure everything that you can see.
And we would like to get the hours and minutes.
So we'll say time dot split.
This is going to give us two different values.
The first one will be the hour and then the other one will be the minutes.
Then we can declare the meeting date where we'll create a new date with this date coming from the form
data.
And we can set the hours just like that.
We would like to get a random ID from this random call.
This is something that we have done previously and we're going to call I mean we're going to create
a default call and giving it a random ID.
Then we can call our method.
Once again this is something that we have done previously.
So call dot get or create with our data which is the start date, as well as some custom data that we
can add such as description and additional details.
Um, we can go ahead and create the inner view in the database by calling our mutation.
So this is what we have just declared above.
This is our mutation coming from convex.
And it expects you to put the title description start time status by default.
This is going to be upcoming because we are trying to schedule a meeting right.
So it cannot be completed or live.
Um, it will be probably a couple of days later right.
So start status is upcoming.
Then the stream call ID, candidate ID, and interviewer IDs.
Once we have done this, we can set Openstate to be false so that the model is closed and we'll show
a toast.
Let's say meeting scheduled successfully.
And then we can reset the form data.
Okay.
So that's going to be it for the try block.
Now in the catch we can console log the error and maybe show a toast to let the user something failed.
And that's entire thing is going to be it for the schedule meeting function that we'll be using.
So almost 60 lines of code.
And it's not that much actually when you take a look at it we have some validations and we are extracting
some data, preparing it so that we can create a call in the stream dashboard as well as in our database,
so that we can keep track of the state, who is the candidate, who is the interviewer, etc. then I
would like to have two different functions that are going to be needed to be able to select a candidate
and to add an inner reward.
So if we add this inner reward, we should be able to delete that as well.
Right.
So we'll have two different functions to be able to make this work.
So the first one is to add an inner river to our state.
Basically, we will keep the previous state and then add this new one to the very end.
Then in the other function, which is to remove an inner river from the state, we're going to keep
all the previous ones, and we are going to filter out the current one that we are trying to delete.
So we have just copied and pasted 100 lines of code.
I hope you don't mind it.
This is nothing.
Then basic react.
So I think I would like to save time rather than spending it by typing these out.
So if you were to type this out, I believe this should be taking at least ten minutes up until now.
So we're going to say selected inner rivers.
We would like to grab those values.
Right.
And now here this as it could be possibly undefined.
And we can go can go ahead actually fix this.
We will say, if this is the case, maybe we can just have an empty array and we can do the same thing.
I believe for this one.
Now we should be able to get rid of that error.
Then we'll try to find the available inner reverse.
I will go ahead paste this.
And that's going to be it for everything that we would need before the return statement okay.
So let's say return a div with some classes.
Let's say container maximum width of seven xlarge.
Center this with max auto padding of six space y of eight.
It should be inside.
I'll have one more div with let's say class name of flex items centered and justify between.
Then.
Um.
Inside this div we will have one more div.
Let me just put a comment.
I'll say header info and I'll say a div.
We will have one p tag as well as an H1.
So inner views and then this p tag that you can see on the UI.
So we have just built this part.
Now we're going to build this button which is to actually open up the dialog.
Okay.
So after this div I'll just say dialog component and we can say dialog.
Let's try to import it from the components.
And this is going to take two different states or props I should say the open prop as well as on open
change is going to call the setter function.
Then we would like to have the trigger which is going to be this button, that green button that you
have seen in the image.
After the trigger we can have the dialogue content.
So I'll say dialogue content import this and this will be taking some classes that I'll just basically
copy and paste.
There we go.
We are making this to to be responsive.
And inside we'll have a dialogue header component with the title itself.
Okay.
Let's save to get this formatting.
Then after the header component we'll have a div.
Let's say class name of space y of four.
And then padding y of four as well.
Inside of this we can just get the inner view title state.
So we are basically trying to build this part.
And we're going to go one by one.
Okay.
So you can find this comment.
And below to it there will be a div that you can copy and paste.
So five lines of code.
We have a label as well as an input within placeholder.
And then the value as well as the on change method.
So after this div we're going to go ahead and create one more comment.
Let's say inner view description.
Once again you can find it, copy it and paste it, which is going to have a text area component and
looks like we don't have this.
So let's open up our terminal and try to install it from CDN.
I'll say NP chat CDN at latest add a text area component.
Okay.
So now we can import this one as well.
So after the description we're going to have the candidate which is going to be a select element.
Okay.
So you can copy this paste this down and let's try to import the select the select trigger component
the content as well as the value.
And finally the item and then the then the user info icon it should be.
Right.
User info.
Okay, so this is actually going to be a component because we'll be using it a couple of different times.
So this is the user info component I believe.
Let's try to create it under the components.
Okay.
For now let's leave it like this and we will import it.
Okay.
Now here it says um.
Okay.
So I think this is complaining because we didn't set the type here.
We'll handle this.
But after this candidate we would like to add the inner viewers.
And I will go ahead maybe grab this one as well which is a little bit more longer, but let's see.
So we have this x icon.
Let's try to import it from Lucid React.
We have the Userinfo component once again.
And other than this we are basically um we are basically trying to render the selected inner viewers
with this with this markup.
So we have a bunch of different classes as well as a button to be able to delete it from the state.
That will call the remove inner function.
But other than this we are showing the Userinfo component.
And then if there if there is any more available inner viewers, you would like to render it as well.
So I know this might look a little bit complicated, but we'll just see it in a second.
Okay, so if there are more inner rewards that we can add, we can display it right here.
So actually I'll go ahead and build this component.
Then we can try to see the UI.
So this component will be let's say first this is going to take an take a prop called user.
And let's say this user will be type of user.
But how can we get the user type that is coming from convex.
Well basically we can say type user and call this document.
Here we can pass the table name.
So from the users now you can see this user has all the fields that a user has in our database such
as the underscore ID and creation time.
These are the ones that will be created by convex by default.
But these are the ones that we have in our schema right.
So let's actually double double check this.
So we have the name email image role and clerk ID.
And this is exactly what you can see when you hover over this.
Okay.
So that's going to be the user type, and in the return statement we can show a div with an avatar image
component.
So let's say this avatar should be coming from components.
Okay, so why maybe we don't have the avatar component.
Let's see I thought we have it but looks like we don't.
So let's go ahead and get this.
We'll say add avatar component.
Okay.
Now that we have it this should stop complaining.
And we'll get the user circle icon.
So that's the user info component.
Let's try to see the output that we have.
Okay.
So for some reason we can see the dialog on the right hand side I will refresh.
Okay so this does not look right.
We need to fix this.
So I have paused the video and just debug this a little bit.
And I have realized instead of getting this from the components, I am getting it from the radix UI.
So that's why it is crashing.
I will go ahead and delete this complete line and instead have this dialog component or dialog content
coming from the components folder.
So let's save and test this out.
Now it is working as expected.
We can see the title description candidate right.
We can select it.
And we can see the inner rivers in our database.
We only have one interviewer right.
So let's try to make this an interviewer as well.
So let's see what we're going to get.
Okay.
Now as you can tell we have more inner rivers that we can select.
And if you want to remove them we can remove it.
So that's what I meant when we built that function.
But now I'll go ahead and make this user to be a candidate.
Okay, so this is how that look, right?
Maybe we have a little bit more space here that could be fixed when we add the calendar as well as the
time component.
So let's go ahead and try to build the rest of this component.
So I will head over to the VS code.
And let's scroll to the very bottom where we had.
Let's just shrink everything.
We had the inner viewers at the very bottom below to it.
I will have the date as well as the time.
So here I will have a div first with some classes such as flex and gap of four.
And then I will I would like to say the calendar component.
So here once again we'll have a div.
Let's say class name space y of two.
And then I will say we'll have a label component.
And maybe I can just copy and paste it.
Instead of typing this out, I can walk you through it.
Okay, so we have a label that says date and we'll be using the calendar component.
And these are the props that are coming from the documentation.
So let's go ahead and actually double check this.
I will say calendar.
Okay.
So this is the component that we would like to import into our code.
So where we can have this single date right.
And these are the props that are coming from the docs as you can tell.
Let's go ahead and copy this and paste it into our terminal.
So I'll go ahead and paste this in.
Okay.
So for some reason this crashes.
Let's see why this is the case.
So I have paused the video and debug this a little bit.
And I have found the solution.
So first you need to type this out where you would like to uninstall the date fns.
So just type npm uninstall datefns.
And then you would like to paste this previous command that you had, and it will ask you if you want
to overwrite the button component and you can just say yes or no.
It doesn't really matter because we didn't change this component at all.
Then it should be good to go.
It will go ahead and get the calendar for you.
So the primary reason for this, I think the data version that Shatkin uses did not work with the one
that we have.
So that's why we had to uninstall the current one and then just install it with the with the calendar
component that is coming from Shatkin.
Okay, I hope that makes sense.
Let's go ahead and import the calendar coming from components UI folder.
Right.
And let's save this and take a look at the UI.
So it says exports is not defined.
Let's refresh.
What does that mean.
So as before, I will go ahead and open up my terminal and maybe try to kill this and rerun this.
Maybe this should fix it.
Let's refresh.
Okay, there we go.
Everything is working as expected.
We can see our calendar where we can select a date.
Select a date.
Now next to it we would like to have some time slots.
Let's go ahead below to the calendar component below to this very first div we would like to have the
let's say time right?
And then I will have a div once again with the same classes space y of two.
And I can get a label that says time and we'll be using a select component.
And this select component will be using the time slots that we have in our constants.
So let's save and take a look at the UI.
This is how that look.
And we can select a time as well.
Okay.
And then after the select after the first div after the second one we would like to add the action buttons.
So I will go ahead and copy this and then paste this inside.
So we have the action buttons with a loader to icon.
If you are creating this is what we're going to see.
But else we will see this text inside the button.
And when we submit this button or when we clicked it we will call this function.
Okay.
So this is how that look.
Let's go ahead and create our very first interview.
So let's say for the title um let's say a coding problem.
And for the description let's say meeting and coding, we can select a candidate.
Interviewer is us and time slot.
Let's say it will be next week today.
Okay.
Let's say schedule the interview.
We have a loading state and there we go.
Meeting scheduled successfully.
Just in a couple of minutes we are going to actually fetch them and display it here on the UI.
But let's take a look at the database.
We should have an inner view.
There we go.
This is the description that we just had.
The title.
It should be at the very end.
There we go.
And the status is upcoming.
Okay.
So that means everything is working as expected.
Next we can build the meeting card component that is going to look like this, where we can see the
status of each meeting with the details.