In this chapter we're going to implement a WAPI connected view displaying the WAPI data. So in the previous chapter we created the WAPI plug-in functionality allowing the users to bring us their API keys which we store in AWS Secrets Manager. And just to discuss one thing from the previous chapter, there was a potential security issue at least I thought, but I didn't fully read the message. So CodeRabbit here actually suggests adding the option to change organization ID. But in our case organization ID should never change for an existing plugin.
That should never happen. But in here they say alternatively, okay if you want that then add a check for that. But I looked at our code and we don't need that. So this is inside of backend convex system AI plugins dot TS. And in here if existing plugin exists they say then check if organization ID is different and throw an error.
But look at what we do just moments before. We use the organization ID index to fetch the same existing plugin. So we are essentially already doing that because this will simply be null, undefined if organization ID is missing or if it's different and then it's just going to create a new one as it should. So our code is 100% fine for this comment right here. Just wanted to clear that up.
Now let's go ahead and let's actually allow our user to see all the models and phone numbers that they have from their connected WAPI account. In order to do that, we have to start by adding the WAPI AI server SDK to our app. And yes, just a quick reminder, try TurboBuild every now and then. So I just tried it after our previous chapter and I can still build normally. It's always good that you try TurboBuild so you catch errors early on.
Let's go ahead and do pnpm f backend add and let's add, whoops that's not it, let's add at VAPI AI forward slash server SDK and once you've added this let's go ahead and let's run turbo dev so that we have convex dev running because we're now going to add some new methods. Let's go inside of packages backend convex private and let's create wapi.ts. In here let's go ahead and import wapi-client and let's import wapi from our newly added package. Let's import internal from generated API and since this will be calling a third-party API which is WAPI, let's go ahead and import action from generated server and in here let's import get secret value from libsecrets and parse secret string from libsecrets because this is where we are going to fetch our saved API keys for this organization and then we're going to initialize the VAPI client using that. Let's export const get phone numbers first.
So this is going to be an action. Arguments are going to be empty. Handler here will be like that. Let's add context and arguments here. Let's go ahead and do our usual check here.
This way we confirm that the user is logged in and that they have matching valid organization ID and now let's go ahead and let's fetch the plugin to see if it exists so that we can obtain the secret name from the database because remember what we have to fetch is this from our plugins database here we have to find the plugin so that we can get the secret name and using that secret name we can call getSecretValue and that is going to return the values here private API key and public API key so let's go ahead and do that now Once we've confirmed that we have the identity, we're going to fetch the plugin. But since this is an action, we can only do that using the internal methods. So let's define const plugin await context run query internal dot system plugins get by organization id and service. That's right, we already have that. We developed it previously.
You can see it right here. If you don't have it, just in case, it's inside of the system folder. So system, you should have it. Plugins. Get by organization id and service.
The organization id is org id. Let me just fix the capitalization. And service is wapi. There we go. In case plugin is missing, let's throw new convex error here.
Code not found. And message, plugin not found. Meaning that we cannot fetch phone numbers for this. And now let's go ahead and let's get the secret name which will be plugin.secretname so we can fetch the secret. Const secret will now be await get secret value and pass in the secret name.
Now this will be a type of get secret value command output so in order for us to destruct the data secret data we have to use our parse secret string. And in order to make this strictly typed, let's go ahead and define what we expect to be saved here. So what do we expect to be saved inside of here? Well, we can easily check that by simply going inside of the secret value and we know private API key and public API key so we can add it here. This and public API key and inside of here pass in the secret.
Let's call this secret value, like this secret value. That makes more sense. But usually the way you would know what is the expected type of the secret data from the value would be in the place where you save that. So I think the only place where we actually strictly type this is inside of the VAPI view component inside of here. The form schema actually defines what it is.
Absurd secret, this is the value that we store. Public API key and private API key. Because inside of absurd secret itself here we simply define it as any and that's correct right we don't know what this will be used for this can be for wapi this can be for five other plugins right and they might have different names for that. They might have five API keys for all we know. That's why we don't type it here, but it's important that we know, at least in the WAPI view in the form, when we call absurd secret, what is the value?
So public API key and private API key. And that's the same thing we're fetching now from here. And we can also double check we are the actual secrets manager here. And now let's check if we were not able to get our secret data, we can go ahead and throw the error meaning, okay, even though you have the plugin record, we were just not able to find this in AWS. So let's go ahead and say secrets or let's say credentials not found.
And now let's go ahead and let's check individually if we have both of these keys. So in case we are missing secret data dot private API key or if we are missing secret data public API key in that case let's go ahead again and let's throw credentials incomplete please reconnect your WAPI account And now we can finally define the WAPI client here using new WAPI client. And usually what you would do here is you would do token process.environment WAPI secret key, right? That's how this works. That's how you would usually do it.
But we already explained the problem behind doing this in the chapter six. The problem is WAPI has a shared knowledge base per API key. So in order to allow our customers to have their own knowledge bases, which are private and secure, as well as their own phone numbers, their own assistance, workflows and tools, we need to allow each of them to bring their API keys instead of using our API keys. So now instead of doing this we are simply going to do secretData.privateApiKey. As simple as that.
And now that we have that users of API client we can fetch that users phone numbers. Like this. Await WAPI client phone numbers list. And let's return phone numbers. There we go.
And let's see if this function will work. Seems to be working. Let's check once again. Perfect. Convex functions ready.
Amazing. Now let's go ahead and let's copy this and well let's paste it above here. We're now going to do the exact same thing but we're going to fetch assistance. So let's go ahead and rename this get assistance. Assistance like that.
Same things here. But instead of fetching phone numbers it's going to be assistants like this. I don't think there's anything else we have to do so pretty much the same. Perfect. And we actually don't need the arguments here at all and we don't need the arguments in the one below either.
Perfect. Now that we have that, let's also confirm this all works, perfect. Let's go ahead and let's create the hook to use these two. So the problem with these is that they are actions but we need to use them as if they were queries. So the way we're gonna do that is by going inside of app, web, modules, plugins and let's create a new folder called hooks.
And inside let's create useVapiData.ts. And now let's go ahead and import useAction from convex react. Let's import useEffect from react, useState from react. Let's import toast from Sonar and let's import API from workspace backend generated API. Let's export const use WAPI phone numbers.
And let's go ahead and define the return method here. Actually, we didn't have to, I think. We can just go ahead and define some states here. So data set data will be use state. But it would be helpful to have the type of this data actually.
Let's say type phone numbers, type of API private VAPI get phone numbers, underscore return type. And then assign phone numbers here. Like that. Then add is loading, set is loading use state and true by default then error set error use state a type of error or null and set it to be null as default. Now let's get the getPhoneNumbers through our use action.
And let's call API private VAPI getPhoneNumbers. And now let's grab our useEffect method here. And first things first, let's fetch the data. So let's create an asynchronous method here. Let's open try, catch, and let's open finally.
Inside of try, set is loading to be true. And in the finally, let's reset it back to false. Inside of catch, let's grab the error here and let's set error. Error as error. And let's toast.error failed to fetch phone numbers.
In the try method let's go ahead and grab the result by using await get phone numbers from the action defined above. Set the data to be the result and you can see the result is a type of phone numbers list response item. So we could, yeah, we could also use that. I'm directly using the literal or literal response response return type of the API call but this seems to be working I think because if I change this to like string Yeah, then you can see this doesn't match but if I keep phone numbers, then it matches I've yeah. Okay.
Let's just continue like this now and let's set error to be null And now let's call fetch data within this use effect and let's pass in get phone numbers here. I think that's the only thing we are using. And what we are returning. Will be the data is loading and error. So our small little version of React query hook, right?
And let's see. So use WAPI phone numbers cannot be named without a reference to this. So what is this? This is a kind of odd TypeScript error that I encountered exclusively in Monorepo. So I think this is because of the monorepo architecture.
The fix is quite simple actually and I also got this error later at the end of this chapter. We're going to try turbo build. I actually also got this error in my convex functions except they weren't typed here. So the error in here actually is that I have to do the same thing that I have to do here. If I resemble a third-party app, I have to add the return type of that because in here we are returning vapi.assistant right so I should be doing the same thing here so the way you can fix this is by modifying the return type here and strictly specifying it so data will be phone and numbers is loading will be Boolean error will be a type of error or null and you can see that this actually fixes it so it needs to have a return type and now that we have this let's go ahead and add assistance.
Get assistance. And let's copy this entire thing. Let's paste it here. This will be use of API assistance. It will use the assistance.
This type will be assistance. It will call get assistance. And let's rename this. And let's rename the error message. So they are identical, right?
Except calling different API endpoints. Perfect. We now have these two useful hooks for us to work with. And I'm actually super interested in this. So I want us to stop now and I want us to try TurboBuild.
So you can see that I tried TurboBuild just before this chapter and I'm super interested if now I will get some errors maybe. Because I kept getting failed builds because of this exact error that was happening here which we just fixed by adding a return method but I got them here in my convex. This was the problematic part. It seems like everything is normal for me here. But just in case, I will show you how I fixed it in case you are getting those errors.
So inside of here, get assistance What I did was I added promise and then I simply described what we return and that's VAPI phone number numbers list response item and then an array of those. My apologies This is true but not for this exact action for the one below. So let's copy that here and let's assign it here. There we go. So forget phone numbers.
This is the promise that we return. You can see how no errors regarding that that's perfectly fine now let's go ahead and fix this for the assistance here so this will be very simple wapi.assistant just like that So now we have added explicit return types for our actions which are returning direct third-party libraries. So let me try TurboBuild again just to confirm that this didn't accidentally mess it up but yes when I was initially developing I kept getting errors here because of that until I added this, only then did it start working again. An alternative way to fix this is by literally adding any type of explicit return method. The problem is with not having a return method.
You can see that in here I didn't even reference the WAPI API. I'm literally referencing my convex return type here. Still works perfect. Let's go ahead and do TurboDev here and let's continue developing on our way. Now that we have these two hooks, it is time for us to create the WAPI connected view component.
So we just did this and we just did this. Let's now go back inside of our apps, web, modules, plugins, UI. And in the components, let's create a VAPI connected view. Let me just fix this connected. Let's go ahead and add all the imports that we are going to need.
Starting with useClient and after that let's import all the icons. Bot icon, phone icon, settings icon and unplug icon. After that let's add image and link from next. Then let's add use state from react. Let's add button from workspace UI components button.
Let's import card, description, header and title from our card component. And let's do the same thing for tabs, including tabs, content, list and trigger. Now let's create the interface for this component. It's going to have one prop on this connect, which will be a required method. So VAPI connected view props.
Now let's go ahead and let's quickly define and export this component. Like this. Vapi connected view has only one prop. In here I'm going to set the active tab and set active tab using state and by default it will be phone numbers and then in here let's go ahead and let's return a div with a class name space y of 6 let's add card, card header let's render div here and the class name flex items center and justify between let's go ahead and render another div here with a class name flex items center and gap four Now in here let's go ahead and let's add an image and let's do alp wapi class name rounded large object contain height 48 width object.contain height 48 width 48 source WAPI jpeg and let's leave it like that. Now Let's quickly go back inside of our WAPI view here.
And in here, where we conditionally render connected, let's add our new component, WAPI Connected View. And on this connect, let's add handleSubmit. Because this will then open the remove dialog if we have the WAPI plugin. So now if you go inside of your localhost 3000 here, let me just refresh so my component here gets compiled and we should see our new component that we are building. There we go.
That's exactly what we've built so far. So continuing instead of WAPI connected view here, below this image Let's add a new div. Oops, let me add a div. Let's add card title, WAPI integration. Let's go ahead and add card description.
And inside of here, something descriptive about what we can do with this dashboard. So manage your phone numbers and AI assistants. Now right here, go ahead and add a button. Disconnect. Give it an unplug icon And give it a class name.
Actually, we don't need any class name here. I think unplug icon is enough. And give this an on click of on disconnect. And size of small. And variant of destructive.
There we go. And now you have an option to disconnect your WAPI plugin. And I think it would be a good idea to actually implement this right now because we already have everything we need here. So we're gonna go ahead and go back inside of the WAPI view here and it should be quite simple to implement this. Let's go and let's copy our WAPI plugin form and let's go just below here and paste it and this one is going to be called WAPI plugin Remove form.
It will have open, set open. Instead of upsert secret, we're gonna use remove plugin. Use mutation, api private plugins dot remove. We already have it. Perfect.
Remember when we added it, I told you to do it right away because we are going to need it here. And now we actually won't need form at all that's the great part. So instead we can just do remove plugin and service wapi because the rest of the information like organization id is all coming from auth after that set open to false WAPI plugin removed and the catch can stay the same. And the dialog will be a little bit simpler. So this will be disconnect WAPI.
And for the dialog description, let's add something simpler here. Are you sure you want to disconnect the WAPI plugin? And then you can remove the form entirely. And let's go ahead and just add DialogFooter. Let's add button.
Disconnect. OnClick. OnSubmit. Variant. Destructive.
So keep in mind how this will not remove the secrets from AWS Secrets Manager, it will simply remove the plugin. So my choice for this was I feel like it's safer not to remove AWS secrets just in case the user accidentally disconnects because this is technically just a disconnect option. It isn't a remove values option. I feel like semantically this is correct. I don't know.
Now let's add Vapi plugin remove form. Open will be remove open set open will be set remove open. As simple as that. And instead of calling this handle submit let's call this toggle... We can just call it...
Yeah toggle. Toggle connection. And passing on disconnect toggle connection and in here on submit toggle connection. And now when you click disconnect you will get a prompt. Are you sure you want to disconnect the WAPI plugin?
And carefully look here and you will see that when I disconnect the WAPI plugin has been removed. I no longer have any data here. But my secret has not been removed right so I still have access to this last secret here you can see it's right here and then if the user decides to connect again so reconnect one two three reconnect three two one and click connect What we've just done is we created a new plugin in our database but we didn't spam this API endpoint for AWS. So you can see I don't have any new secret which wasn't retrieved before so it's not possible that a new one was just created. Instead this is the exact same one from before because the secret here is exactly the same.
WAPI and that Organization ID. Reconnect 3 to 1, reconnect 1 to 3. Exactly what we wanted. Amazing. And now we can go back inside of WAPI connected view and develop it further.
So we just finished that card actually. We no longer have to develop anything in this card. Now let's open a new card. Card header. Let's add a div here.
Let's go ahead and give it some classes here. Class name, FlexItemsCenter, justify between. Another div. Class name, FlexItemsCenter. Whoops, my bad.
FlexItemsCenter. Gap 4. Class name flex items center whoops my bad flex items center gap for inside of this div let's add one more div with settings icon inside Give its outer parent div a flex size 12, items center, justify center, rounded, large, border and background color of muted. So now you should see your settings that looks like this. And for the settings icon, let's give it class name size 6 text muted foreground.
Perfect. Now, outside of this div, open a new div and inside let's add the card title and the card description, same as above. So we can just add it here. And this will be widget configuration. And in here we will see set up voice calls for your chat widget.
And then outside of this div here, we're going to add button, as child, link, So we are using as child because then this button component will become an anchor component. And the href will lead to forward slash customization, which is a page we yet have to develop. And that will be the settings page. And we actually don't have to add anything and just configure. So now we can see that we are basically telling the user who just connected this WAPI plugin, Great!
In here you can connect whether it's connected or not connected. But if you actually want to add this to your chat widget, you have to go inside of configuration which will redirect the user here, which we don't have yet. Perfect. Exactly what we wanted. And now let's develop the actual tabs which will show phone numbers and all the other things.
So outside of this card here let's add a div. Class name, overflow hidden, rounded large, border, bg, background let's add tabs now the tabs here will have the following props class name gap0 default value phone numbers, phone dash numbers on value change set active tab and value active tab keep in mind that this phone numbers needs to match exactly without a typo this use state phone numbers instead of here let's add tabs list Now I'm going to give this a class name grid height of 12 full width grid columns of 2 and padding 0. Inside of this tabs list, I'm going to go ahead and add a tabs trigger inside phone icon and write phone numbers inside. I'm going to give this tabs trigger a class name of full height rounded none and value phone numbers. Now let's go ahead and let's copy this trigger here and change this to be bot icon and change this to be assistance, AI assistance.
And the value will be assistance. And now you have phone numbers and assistance to switch to. Outside of the tabs list, let's add tabs content with the value phone-numbers. And inside let's simply write to do phone numbers. Let's copy this, change the value to assistants to do assistants.
And now you can switch between the two. Perfect. Now let's go ahead and let's develop the WAPI phone numbers tab and once we develop it we can literally copy it for the assistance tab. So inside of the UI components, let's create wapi-phone-numbers-tab.tsx. Let's mark it as useClient.
Let's go ahead and import all the icons that we are going to need. So that's going to be check circle icon, copy icon, external link icon, more horizontal icon, phone icon and X circle icon. After that let's import toast from Sonar. Then let's import badge from Workspace UI components badge. Let's import button from Workspace UI components button.
Let's import the drop-down menu content item and trigger and let's import the table. Table body, cell, head, header and row. And finally let's import use WAPI phone numbers from our hooks use WAPI data that we've created previously. There are not going to be any props so let's immediately do WAPI phone numbers tab And in here let's destruct data and let's remap them to phone numbers and let's grab isLoading all from useWAPI phone numbers hook. Let's define copy to clipboard method text string Let's define copyToClipboard method, text string, and actually let's make this asynchronous, let's open try, catch, toastError, failedToCopy, and in here await navigator clipboard writeText, text, and then toastSuccess, copiedToClipboard.
ToastError failed to copy. And in here await NavigatorClipboard.WriteText. And then ToastSuccess copied to clipboard. Now in here let's return a div, class name BorderTopBGBackground, table, table header, Table row and then individual table head here, which will say phone number. Then in here class name px6py4 font medium.
Actually we don't need font medium. Let's go ahead and copy this table head. Change this one to be name. Then this one to be status. And the last one will be actions.
Change the actions one to use text right outside of table row and outside of table header add the table body. Inside of here open curly brackets open parenthesis, execute an empty function inside and then execute that again. So this is a self-invoking function. We are practically simulating a component inside. Because what this will allow us to do is the following.
We can now do if isLoading, return a specific thing. Table row, table cell, and inside loading phone numbers. The table cell will have a call span of 4, so it's taking all the 4 columns that we have. And it will have a class name, Px of 6, Px of 6, Py of 8, Text Center and Text Muted Foreground. The next thing we're going to do is we're going to copy this.
And we're going to check. Let me just see. Did I do this correctly? Okay. We have to end this if here and then it's correct.
Okay. This will be if phone numbers dot length is equal to zero. In that case, we're just going to say no phone numbers configured. And finally let's return the phone numbers. So return phone numbers dot map.
Get the individual phone. Add table row here. Class name, hover, BG muted with 50% opacity, key phone.id, table cell, class name px6py4, font medium, actually no need for font medium, div, class name, flex items center, gap 3. Inside, phone icon. Let's go ahead and give it class name, size 4 and text muted foreground.
And next to it a span phone.number or not configured. And let's render this under font mono. Outside of this table cell, let's go ahead and let's copy it actually. Like that. And This one will be simpler.
It's just going to render not phone number but phone name or unnamed. Let's copy the table cell again. This one will be different. So this one will say badge. We're going to have a class name, capitalize.
And we're going to have different variants. So variant, whoops. Different variants. So variant, whoops, if phone.status is active, we're going to use default, otherwise destructive. So we know the status of the phone.
And then phone.status is equal to active. In that case, check circle icon, class name MR1 size 3. Go ahead and copy this and do the same for if it is not active then use X circle icon and then finally render phone.status or unknown. Like that. And then the last one here we need is the...
Actually we won't need actions at all. Because the way we are going to develop our widget customization. Yes, so we don't need the actions and that means change the call span here to 3 and here to 3 as well. And that would mean that we are done. Perfect.
Now let's go back inside of here. To do phone numbers, let's render vapi.PhoneNumbersTab. Like that. And by default, we are going to get errors. Why are we getting errors?
Well, the reason we're getting errors is because we have fake API keys. We can't fetch anything. So let's go inside of our VAPI.ai. You can use the link on the screen. Let's click open dashboard here and just remember if you don't have WAPI configured, chapter 6 go ahead and take a look at it.
In here we build the customer support agent and we have phone numbers and things like that. So let me just log in and here I am and now just make sure that you have at least one assistant. So I have Tom and Riley here and inside of your phone numbers confirm that you have at least one phone number here. Perfect. Now that you have that go inside of WAPI API keys.
The last thing we actually did is we deleted all API keys because we stored them insecurely. So now let's go ahead and add key here and I'm going to call this echo public key. And I won't select anything else just create public token and then I'm going to okay let's just create another private key so echo private key and again I'm not going to select anything just create that perfect and once we have that let's disconnect here Let's refresh for good luck and let's click connect. Now I'm going to copy my public API key from here and I'm going to add it in the public field. Yes, we have to turn this into a password field.
I forgot about that. And let's do the same thing with the private key here. And now let's click connect. And just like that, we have working phone number fetch from WAPI. This is the magic of bring your own keys method and this is the magic of our white labeling method, right?
So this will allow every single one of our customers to connect their own WAPI and load their own phone numbers. I honestly think this is amazing because we do so many things. We store the database table as plugin, but we actually store it inside of AWS secrets manager and we managed to encrypt that and decrypt that and it's super secure and it's super cool and it works, it's amazing. And this tells us the status of the number, is it ready to use or not? And the exact name, Perfect.
Now let's go ahead and do the same thing with AI assistance so that we can finally wrap up this chapter. So the cool thing is that we can just copy WAPI phone numbers tab and rename it WAPI assistance tab. Now inside of WAPI assistance tab we can actually remove the unused dropdown menu here. Unused button, unused three icons here. Let's go ahead and change this to use WAPI assistance.
WAPI assistance tab. The data here will be remapped to assistance. We don't need copy to clipboard also. And now let's work from here. So in here we're not going to have phone number, we're going to have assistant.
We're not going to have name, we're going to have model. We're not going to have status we're going to have a first message of the assistant perfect so loading assistance assistance dot length no assistance configured like that Now in here we are iterating over assistance and now let's go ahead and check well field by field. The first one is going to be yes this is also assistant. So assistant dot ID bot icon instead of phone icon. Let's import that from Locid React.
This will use the assistant.name or it's going to be unnamed assistant. And no need for font mono here, but everything else can stay the same. Now in here, we are going to do assistant dot model question mark model because that's how you access the name so not configured. Otherwise if we can't find it and let's wrap this inside of a span here and let's give it a class name of TextSmall like that and then the last one we're going to do here is not nearly as complicated as the badge. Instead, we are going to add a span again and the render assistant dot first message or no greeting configured.
And let's give this a class name, truncate text muted foreground and text small like that. And I believe that marks the end of this component too. Let's remove all the unused things. So these three icons This and this. Let's go back instead of WAPI phone numbers and also remove all the unused things.
So copy external and more horizontal button. This we're also not going to need toast. You can remove it And remove copy to clipboard. There we go. Perfect.
And now let's go inside of WAPI connected view and let's add WAPI assistance tab, self-closing. And there we go. Tom and Riley as well as their first message here. Let me just check grid calls to did I, okay now this is fine. VAPI assistance tab.
I was hoping that the message would be truncated maybe paragraph instead of span no maybe line clamp one. Maybe it's not a problem. I don't know. Not sure why it's not listening to me because this is the exact code that I used and it did work. Okay, I think we need to do maximum width of extra small.
Yes we need to limit how wide this can go. There we go. And now it will have a limit. But you can choose if you like it being displayed it scrolls nicely it's fine. And now you can see all of your assistants connected with WAPI and your phone numbers.
Amazing! And using this method, you can also add tools, outbound, workflows, whatever you want your users to be able to use WAPI for, which is absolutely amazing, you will be able to add here using the exact same method. I'm super happy with how this turned out. And what we have to do next is develop the widget customization, which will allow us to select what phone number and AI assistant to use on the chat widget screen. Before we wrap up the chapter let's quickly go back inside of WAPI view and let me just properly give our type here password so we finally fix that issue.
Amazing! So let's go ahead and go back to here. We officially did this, right? The users can now bring their own API keys. We store them securely and every single tenant now has their own knowledge base, phone numbers, assistant tools, perfect.
And they don't even occur any costs on our side of the app. They are responsible for their costs of the WAPI. Amazing! Let's go ahead and mark this as completed as well and let's merge these changes. 25 WAPI data.
Let me go ahead and stage all of my changes here. 25 WAPI data. Let's commit. Let me open a new branch. 25 WAPI data.
Let me publish the branch. And as always, Let's go ahead and review our changes to see if we had some oversights and overall quality of our code. And here we have the summary. We introduced a user interface for managing WAPI integration, including separate tabs to view and manage AI assistants and phone numbers. We added tables to display lists of connected assistants and phone numbers with detailed information and status indicators.
We enabled plugin connection and disconnection via dialog interfaces with masked API key inputs for security. And we added toast notifications for successful or failed plugin actions. Amazing. So I think that the sequence diagram is pretty clear to us right? We already know what we're basically doing.
If tab is assistants, we use use WAPI assistants and the backend calls get assistants and then WAPI API fetches those assistants. I think that is pretty clear to us. In here we have various comments and this is an important one. Yes, we should absolutely have a variable like this because imagine if you are in the middle of fetching data and quickly switch to a different tab. That will cause setState set in an unmounted component warning inside of your console.
So yes, this is super important for us to do. I will do that in the next chapter. Same thing here in the assistance and also it recommends not adding the function inside of the dependency array because it will run on every render since use action returns a new function reference each time. Very interesting. I will look into that as well.
Perhaps we don't even need anything in here and then it will just be a simple onMount function. Very, very good comments here. And now the rest of the comments in here are mostly error handling, right? Of course, it recommends handling errors in a better way, handling them inside of our tables. If you want to, you can of course do that.
We have the error object so you can display it then. That I'm mostly okay the way it is right now. In here it recommends refactoring the duplicated code because we have get assistance and get phone numbers. And yeah, the code inside is identical in like two functions a pretty large chunk So we could abstract it technically Except if you want to throw Different errors, I guess Yeah, we could do that We definitely have to start abstracting some code. I'm repeating myself too much, but it is super simple code.
It's nothing complicated. In here again, it recommends handling errors in a better way. We could do that too. But since we're using that as queries, but yeah, I mean, obviously handling errors is never a bad idea. I will look into all of that in the next chapter.
In here it made a mistake. Version 10, 0.10 is definitely the newest version. I think it's registry has some incorrect information here, but super, super useful for us to know that we have potentially broken hooks here that can cause maximum update depth or some other errors. So we will fix that in the next chapter. Let's go ahead and let's merge this pull request here.
And then let's go ahead and switch back here into main. And let's push and pull to synchronize the changes. Once the changes have been synchronized, let's go ahead and click graph and confirm. So we went 22, then 23 was AWS, 24 was WAPI plugin and 25 WAPI data. Amazing, amazing job.
I believe that marks the end of this chapter and see you in the next one.