In this chapter, we are going to implement the meetings into our project. This chapter will include setting up the schema, module, procedures, and the meetings pages. So let's start with our schema. As always, ensure that you're on your main default branch and go ahead and synchronize changes just to make sure everything is up to date. After that go inside of database, schema.
And in here to make things easier let's copy our agents schema. Let's paste it. Let's rename this to meetings. Let's rename the actual table name to meetings here. The ID field stays exactly the same, the name as well.
User ID reference, exactly the same. And then we can copy the user ID reference and simply add the agent ID reference and make sure to name this table agent underscore ID and the reference will be to the agents dot ID table Besides the agent reference, which also has the onDelete cascade, meaning if an agent is deleted, this meeting will be deleted too, let's also add a status. Now the status will be a special enum, which we have to create. So let's go above here and create a const meeting status to be a type of PG enum from drizzle ORM PG core. Inside of here let's go ahead and add meeting underscore status and open an array.
In here, we're going to set upcoming, active, completed, processing and canceled. Now we can use the meeting status as our type for the status here. Meeting status, column name status, required, and default upcoming. Like this. We are not going to have instructions, but what we will have is the startedAt and endedAt timestamps.
So make sure to fix this. This will be startedAt, this will be endedAt, and they will not be required and we are not going to default them. So just timestamps like this. Besides that, let's also add transcript URL, which is a type of text, transcript underscore URL, copy and paste this and make a recording URL. And add recording URL here as well.
And last one will be the summary, which is a type of text summary. So none of these fields here are required, because all of these will exist only after we switch to completed mode, right? Only after the meeting has been had, will we be able to append the proper status started at, ended at, transcript URL, recording URL, and the summary. Great. So make sure you have the agent reference, make sure you didn't forget to change the name of any column here, make sure none of them are repeating.
And now let's go ahead and push this to the database. So I'm gonna go ahead and do npm run database push like this. And this will add the new schema to our database and I seem to be having an error here meeting status does not exist So let's see what I did incorrectly here. So pgEnumMeetingStatus, first of all, let's also add export const here. I think we need to do this as well, simply because we are using the entire schema in some places.
But let's just save this file, let's shut down our app, and let's try again. There we go. So I'm not sure which one of these changes did it. Maybe it was the export, maybe it was just saving the file again and shutting down the app. But yeah, just try one of those and try npm run database push again and no reason at all for this to fail.
Great, So now we have added our meetings schema. Now let's go ahead and let's add the meetings pages and the meetings module. So I'm going to go inside of source app folder dashboard and I'm going to add meetings here and inside a page.tsx page, div meetings page. Just like this. And inside of here let's add individual meeting ID, page.dsx, another page here, and a div meeting ID page.
There we go. So now that we have added this, we can go ahead and do npm run dev on our app again. And we can go to localhost 3000 here, wait for it to load, and we can now click on the meetings and we will see the meetings page. And if I manually change my URL to forward slash meetings slash 123, I will see the meeting ID page. So let's go back to the meetings page.
And now let's implement our module so that we can actually see the JSON of our data. So let's go inside of modules here. Let's create meetings. And inside of here, let's create the server module. And inside procedures.ts.
Let's keep our agents server procedures open so we can copy and paste and speed things up. So let's start by copying everything and pasting it in the new meetings procedures here. And let's rename this to be meetings router. And for now, let's remove update and let's remove basically all except get one and accept get many. So that's the only thing we're interested in.
We are later going to adapt the create, update, remove, and similar ones. There we go. So meetings router. Now let's go ahead and improve the get one procedure here. So get one is a protected procedure is looking for ID instead of existing agent it will be existing meeting here and it's not going to have a meeting count so you can remove that and you can leave this as it is and it will be from meetings So you have to change meetings in all instances here.
The easiest way to do that is to simply remove the agents imports. You will have errors and you will know all the places you have to fix things. There we go. So everything's exactly the same. Existing meeting, existing meeting and meeting not found.
Or to get many similar. Let's go ahead and remove this. Leave this to be meetings from meetings, meetings user ID, meetings name equals to search order by meetings created at meetings ID, and the total is counting the meetings with the same query here. So luckily the fields are exactly the same so we don't have any issues here whatsoever. And we can remove the SQL import here.
There we go. So we have a dead simple get many and get one procedures here. Now what we have to do is we have to go inside of the RPC routers, and we have to add meetings router from modulus meetings server procedures and call this meetings like this. Now let's go to our page.tsx inside of our meetings here and in here let's return meetings view. Let's build the meetings view quickly by going inside of our modules, meetings, and let's create the UI folder.
Let's create the views folder and let's create meetings-view.tsx. Mark it as useClient, export const meetings-view, like this. And inside of here, go ahead and do the following. Prepare trpc from useTRPC from the client prepare data from use query from 10 stack create query passing the TRPC meetings get many query options and simply pass an empty object here. And here do JSON stringify data question mark dot items.
Like this. Or you can actually stringify the whole data. It doesn't matter. Now let's go to the page and let's import MeetingsView from ModulusMeetingsUIViews.MeetingsView. So now when you hit the Meetings page, you will see the empty state right here.
Now let's go ahead and just add some data here so you can either visit the Neon console or you can visit the Drizzle Studio here so we can go inside of our project here go inside of the tables and let's just add something again if for whatever reason you can't do this, no worries, because we're going to create the form for creating meetings in the next chapter. So go inside of meetings, add record. Yeah, you would now need to... Let's discard the changes. So you need to have at least one agent and just you know paste the ID here, grab a user for example, whoever you are logged in with right and just paste that user ID here and then go inside of your meetings and add a new record for the ID you can just write demo or the name this can be first meeting and then for the user ID you will copy your user ID and add it here for the agent ID copy it and add it here as well.
And for the status, you can use the default, and I don't think you have to fill anything else here, so just click Save Change. There we go. And now we have proper relations with that user and with that agent. Again, if you fail at doing this, no problem at all. We will create it in the next chapter, the actual form for doing this.
But there we go. You can see that it works. We can now see our data here. Perfect. So what I want to do now is I also want to enable the prefetching here just so we don't have to do it later.
So let's go ahead and do the following. Inside of our meetings page, let's go ahead and let's grab the query client using getQueryClient like this. Let's execute it and let's do void QueryClient.prefetchQuery and inside pass in trpc from trpc server meetings get many and pass in an empty object for the query options like this so now we are prefetching that Now let's go ahead and let's add our hydration boundary from 10-stack React query in here. Let's add the state to be dehydrate from 10-stack React query and pass in the query client. Like that.
There we go. Now our page is hydrated and prefetched. So what's missing is the suspense here from react. And besides suspense, the error boundary from React error boundary. Now let's go inside of the meetings view here.
And let's borrow from our agents module, UI, Views, agents view. Let's copy agents view loading and agents view error. And let's paste it inside of our new MeetingsView. So let's rename both of these, well, all of these instances to meetings. So MeetingsViewLoading, LoadingMeetings, MeetingsViewError, ErrorLoadingMeetings.
And import the loading state and import the error state like this. There we go. And now in here we can use a fallback, meetings view loading, and in here we can use meetings view error. There we go. So I'm just going to align all of my imports here.
There we go. Move this here. So you need the meetings view, meetings view error and the meetings view loading. There we go. Which means that now in the actual meetings view instead of using use query you can use use suspense query.
And that will trigger the suspense. There we go. So now when you refresh here, you will see loading meetings. And if you go ahead and try and throw an error somewhere in here, for example, throw new TRPC error code, bad request, and the refresh, You might encounter this maximum depth infinite loop thing, but after it settles down or after you do a couple of refreshes and try again, it will eventually simply render the error. Let's give it a second.
There we go. Perfect. So I think that's exactly what we wanted to do in this chapter, simply introduce our meetings and prepare the basics. And we did it quite faster than the agents, simply because we had a lot of things to copy from. So now let's go ahead and let's create a branch from this and let's merge it.
So I'm going to create a new branch here and I'm going to call it 16 meetings setup. Let me just confirm that is our topic, it is. Perfect. Let's go ahead and stage all changes. And let's write our commit message, meetings setup.
Let's click commit and let's publish the branch. Perfect. Now let's go to our GitHub, let's open up a pull request, and let's see what CodeRabbit has to say about our code. And here we have our summary. We introduced a meetings dashboard page with loading error and data display states.
We added a dedicated page for viewing individual meeting details. Meetings data is now fetched and displayed, including support for pagination and search, simply because we copied the GetMany from the agents procedures. Perfect. So in here we have a more in-depth walkthrough and in here we have a sequence diagram which is identical to the one for the agents so we didn't have to go through it because we didn't really add anything new. Later when we actually add some new filters it will be interesting to look at how it handles that here.
Perfect. And in here it has some comments. Obviously we didn't do anything for the meeting id page. We will have a chapter for that. But you can see how it knows exactly how it's supposed to look like.
So it even knows the new TRPC syntax. This is very impressive because it actually reads from our code because this new TRPC syntax is not something that AI completion models actually know. Perfect. In here it tells us to add pagination parameters. We will add that later when we add the data table and all the filters.
And in here of course it tells us to add the actual data table. We will do that in the next chapter. And in here it tells us to add UUID validation for get one. This is interesting but it's actually not correct because we are using nano ID. If you go inside of the schema here we are using nano ID.
So using UUID for the validation would be incorrect in this case. Perfect and in here it adds some additional validation but I'm okay with the way we are using it right now. Perfect so let's go ahead and merge this pull request right here and let's go ahead and go back to our main branch here and let's click synchronize changes here and there we go that adds the meetings here go inside of your source control graph and confirm that you just merged chapter 16 meetings. Amazing, amazing job. Let's mark this as completed and see you in the next chapter.