In this chapter, we're going to develop the individual meeting ID page. This will include modifying the agent's get one procedure, adding the agent's remove procedure, and adding the agent ID page and the agent ID view. Let's start with modifying the get one procedure. As always, confirm that you are on your main branch. And then let's go inside of our meetings procedures here and find get one protected procedure.
In the select here, after we spread our get table columns, add an agent, which will be a type of agents. And you can actually copy from get many, right? So you can copy the duration here. It will work exactly the same. So just add it right here.
And what we have to add is an inner join here so we are only going to load this meeting if we can find the relevant match between meetings agent ID and agents ID for each meeting that we are requesting. Like that. Great, so that's what we had to do for modifying the agents get one procedure. And now let's go ahead and implement the remove procedure. So I'm going to copy the update procedure because it's quite similar.
Let's go ahead and copy it. Let's paste it here and let's call it remove. Inside of the input here we are simply going to call zObject and requestId of string like this. This will then be removed meeting and instead of update we will call delete. Remove the .set and find where.
So where meeting ID matches the input ID and where the user ID matches the currently logged in user so we know this user has access to modify this meeting. And then let's work with if there is no removed meeting, meeting not found, otherwise removed meeting. That's it. That is our agent's remove procedure. Now let's go inside of the agent id page.
We can find that in source app folder dashboard meetings meeting ID and in here let's go ahead and let's prepare the following props params with a promise of meeting ID inside and make sure that you didn't misspell meeting ID here because that's how you will be able to access it. So be mindful of the case sensitive items, be mindful of any typos. Now let's mark this as an asynchronous method. Let's extract the props and let's get the params here. Then let's go ahead and let's extract meeting ID from await params.
Then let's go ahead and let's add our session protection here. So let's import out from lib out let's import headers from next headers and let's import a redirect from next navigation once you've added that let's go ahead and prefetch the individual meeting So let's get query client from get query client. You can import this from the PRPC server and then void query client, prefetch query, PRPC, meetings, get one, query options, and pass in the id to be meetingId. Add a to-do, refetch, getTranscript, meetings, getTranscript. This doesn't exist yet, we are later going to implement it now let's add hydration boundary here Let's add state to be dehydrate and passing the query client.
You can import hydration boundary and dehydrate all from 10 stack React query. Now in here add a suspense from React. Then add error boundary from react error boundary. Now let's go ahead and assign the fallback here. And let's just do to do.
Make sure to import suspense from react and error boundary from react error boundary. Now let's implement the meeting ID view component. So I'm gonna go inside of my modules, meetings, UI, Views, and I will create MeetingIDView.tsx, like this. Let's go ahead and create an interface here, props, MeetingID. Let's export const MeetingIDView right here.
Let's destructure the props. Meeting ID. Like this. Then let's go ahead inside of here and let's return a fragment and let's return a div here with a class name flex1 py4 ex4 mdpx8 flex flex column and gap y of 4 meeting ID view Then let's go back to the page and let's replace this with meeting ID view and pass in the meeting ID meeting ID. Make sure to import this from modules, meetings, UI views, meeting ID view.
And now when you click on an individual meeting here, let's just do a refresh, you should see the new meeting ID view. Now let's go back inside of the meeting ID view. Let's prepare trpc from use trpc from trpc client and let's extract the data from use suspense query individual use suspense query from 10 stack react query as in trpc meetings get one query options, and pass in the meeting, the ID as meeting ID. Like that. Now that you have that, let's go ahead and do a JSON stringify data null 2.
So let's go ahead and refresh. Let's go inside of meetings here. Let's click here. OK, it seems like something is wrong here. Instead of meeting ID view, we need to mark it as use client.
That's it. That's what we forgot to do. Let's refresh now. And there we go. Perfect.
Now let's build the error and loading states. So these are identical as to all the other places we've used them. So Meeting ID view loading using the loading state and Meeting ID view error using the error state. You can import the loading state from components loading state and the error state from components error state. The title loading meeting this may take a few seconds and error loading meeting please try again later and here I have both of those components added.
Now that you have that added You can go back inside of the page here and instead of using to do you can now use meeting ID view loading and In here you can use meeting ID view error Like this and let's just import it Make sure to add all three meeting ID view the error and the loading So now when you refresh you will have proper loading here and we've already demonstrated error a couple of times so no need to do it again. Now let's go ahead and let's copy from the agents UI components in here. We have agent ID view header. Let's copy that. Let's paste it inside of meetings UI components.
And let's go ahead and rename this from Agent ID View Header to Meeting ID View Header. And in case you think that we forgot to rename this one, no, this is our filter for filtering by agent. So this needs to be called agent ID, even though it's in the meetings module. So let's go inside of our new meeting ID view header and let's modify the props a bit. So instead of agent ID and agent name, we will have meeting ID and meeting name.
So let's go ahead and use that here. Meeting. So let's use the meeting ID here. And the href will be forward slash meetings. And here as well meetings and this will be my meetings.
And this will be meeting name. And I think that everything else can stay exactly the same except of course, meeting ID view header component name. Perfect. So now we can go back inside of the Meeting ID view here and let's go ahead inside of this div render the header component Meeting ID view header. Let's say Meeting ID view header and inside of here go ahead and pass the following.
So the Meeting ID can be simply Meeting ID prop. Meeting name will be data.name and on edit here will just be an empty arrow function and on remove will be an empty arrow function. Let's see what the issue is here. So my apologies, Meeting ID View Header. That's the component I wanted to add, the new one which we just copied and modified.
So now when you refresh here, Your individual meeting ID should now have a familiar looking header. So you can navigate back to all meetings, or you can open the drop-down to edit and delete. Now let's implement the delete functionality here. So that will be quite simple. Let's go inside of the meeting ID view here, and we have to prepare const remove meeting from use mutation.
You can get this from TRPC, my apologies, from 10-stack react query. Inside add TRPC meetings remove and add query options here. Let me just see mutation options like this, add on success here, and on error, like this. Now let's also prepare the query client here, use query client, you can import this from 10 stack react query. And instead of the on success, we're going to invalidate meetings get many like this.
And let's add to do invalidate three tier usage. And then let's also add router here, use router from next navigation. So make sure you import this, like that. And after we do this, let's do router push forward slash meetings. So after we remove it, we get redirected back to the meetings here.
And on error, we can get the error and we can do toast from sonar.error, error data message. Let's do error.data. It Looks like we don't have any code in this one. Let's just not do the error for this one. Now let's go ahead and add our use confirm hook, which we can now reuse.
So in here I will add this. Remove confirmation and confirm remove coming from the use confirm hook. And it has two parameters. First one are you sure and the second one the following action will remove this meeting. And use confirm can be imported from here.
Let's remove the toast sonar here in case you've had it and let's go ahead and add this here like that and now let's go ahead and let's implement the handle remove meeting. So handle remove meeting is an asynchronous method which is going to await confirm remove from our use confirm hook. And only if we get okay are we going to await remove meeting mutation. So now we can handle that and pass it here like that. And now if you want to you can go ahead and try it out click delete and you have a confirmation.
Once you hit confirm this will get deleted and you are redirected back to the meetings page. Now let's also implement the edit functionality. So this will be quite simple. Let's go ahead and let's copy the new meeting dialog. And let's rename it to update meeting dialog.
Inside of here, rename it to update meeting dialogue as well and add one more initial value prop here to be a type of meeting get one. And I think we already have it from the types we do. So this is the get one output like that. Go ahead and structure the initial value here. This will be initial values, not initial value like that.
And then inside of here, this will be edit meeting and this will be edit the meeting details and meeting form in here is not going to have a redirect so it's just going to be an open on change and oh yeah we have to fix this and set this to false and pass the initial values here to be initial values like that and we can do this simpler like this and while you are here remove the router remove this go inside of your new meeting dialog and simply fix this to be false so you can close that dialog. Great. Now let's go ahead and let's render the update meeting dialog inside of the meeting ID view. And let's go ahead and prepare our set state here. So I'm just going to put it here.
So const updateMeetingDialogOpen and setUpdateMeetingDialogOpen, all from useState, which you can import from React, like that. Now, let's go ahead and use this right here in the updateMeetingDialog. So open will be updateMeetingDialogOpen, like that. And we're gonna have onOpenChange to be setUpdateMeetingDialogOpen, So open will be update meeting dialog open like that. And we're going to have on open change to be set update meeting dialog open and the initial values will be data.
And make sure to import this update meeting dialog from components update meeting dialog. And one more thing we have to do is set update meeting dialog open in the header here. So meeting ID view header on edit set this to true. So now this meeting is called test as you can clearly see here. But if I click edit, you can see how it also populates the agent.
But if I call it test two and click update, it should rename to test2. And it does. And if I go back, it's called test2. So that's all thanks to the work we did when we initially developed the meeting form. So it automatically uses update meeting and it refetches itself and get many as well.
Great. Amazing, amazing job. So I'm going to stop this chapter here. And then in the next one, we're going to focus on the UI inside of here and we can start the call very very soon. Perfect!
Let's go ahead and merge this. So I'm going to go ahead and open a branch. 20 Meeting Page. Create new branch. 20 meeting page.
I'm going to go ahead and stage all of these changes. 20 meeting page, I will commit, and I will publish the branch. Now let's go ahead and let's review our changes by opening a new pull request. And here we have our chapter summary. We added the ability to delete meetings, we introduced an enhanced meeting detail view with improved loading and error handling, and we added a header component to the meeting detail view with options to edit or delete the meeting as well as a new dialog for editing meeting details.
We also did some bug fixing such as the issue where canceling the new meeting dialog did not properly close the dialog. Great, so in here we have a more in-depth walkthrough. And in here we have a sequence diagram, but nothing new is really shown here because we did this exact thing when we developed the agent ID view, right? And in here we have some comments such as to implement to do, which we are definitely going to do once we get to the premium chapter. I mean, the chapter where we add premium features to our app.
And in here it's telling us to be mindful of accessibility. So yeah, we could look into this even though I think Shazian handles that by itself. In here it does not have the most up-to-date information. So next headers does return a promise so headers needs to be awaited so this is an incorrect suggestion in this case same thing for params so this is new it wasn't like that before but now the new version is params is a promise and you need to await it. And in here, same thing.
So this is a completely new way of prefetching with TRPC. So it thinks it needs to be a wait. No, it needs to be a void. Perfect. Great.
So now let's go ahead and let's merge this pull request. And after it's merged, let's go back to our main branch and let's click synchronize changes and okay. Let's then go inside of our source control, graph and confirm that we just merged 20 meeting page with all of the changes we just reviewed. Amazing amazing job and see you in the next chapter.