Now let's go ahead and let's install React Played Link. So we can continue to step 2 to exchange our token. So let's do bun add React Played Link or npm install React Played Link. Make sure you run npm run dev or bandrun dev and refresh your app. And now let's go ahead and let's import from React Playdlink a hook called usePlaydlink.
And now we're going to call this token to exchange that so inside of here we're gonna get const played to be used played link and a configuration file so let's go ahead and assign the token like this on success we are going to get a public token back and then we're going to go ahead and console log that public token like this and let's add environment sandbox here and now what we are going to do is we're going to create our const is disabled so let's do it if blade is not ready in that case we're going to disable the button. So we're obviously going to add some more stuff here later but for now let's just do this. So Plaid is not going to be ready if token is undefined so you don't have to worry about this updating. Yes it can update so this is completely fine. So I want you to go inside of use mount and I want you to add a console log of the data here and I want you to have token text here.
The reason for that is because I want you to confirm that you are returning the actual data link token so you avoid any bugs here. And inside of here, we can just keep the public token like this, right? Let's go ahead now, let's go inside of this button and let's give it an onClick here to be onClick. So let's create const onClick to check if blade is ready. In that case, blade open.
Well, we technically don't have to change blade ready because the button is going to be disabled, right? So there we go, that's our on click here. So first before we try that, confirm that the token thing works. So I'm gonna go ahead inside of my inspect element here. Let's refresh our app.
And there we go. This is my token right here, link sandbox. This is how it should look like. Confirm yours is the same. So now that you've confirmed that you know that that's what's stored in the token variable here and that's what's being passed here.
So you can now click connect and there we go we now have our finance tutorial uses played to connect your account. Where did it get the name from? So it got the name from here, from the API route plate. When we define the link token create, we give it the name. So in here we can click continue and I'm going to go ahead and expand this and I'm going to open my inspect element here so we can see the success message.
So I'm going to select any of these banks and I'm going to go ahead and just go through all of these. So just pretend you can just press all the buttons, right? And select at least one account and click continue and then accept the terms and conditions and that will bring you back here. And now you will get a success message and when you click continue, there we go. We now have a public token.
So now, right here, we are on step two and we are about to do step three, right? So we use the link token to open link. This is a component, right? That's what we just opened. And then in the onSuccessCallback, whoops, this is a redirect.
Let me just scroll. So in the onSuccessCallback here we provide a temporary public token. So that's what we just received here and then we have to create another API route public token exchange and then we're gonna get the permanent access token which we can store in the database and then the user is going to use this access token for anything they need like fetching transactions, assets or anything else Plaid offers. So let's go ahead and exchange this public token now. So we're going to have to go back inside of our Plaid and we're going to create another post route.
So go inside of here API played we have this existing post route so let's go ahead and copy this and paste it below and this one is going to be called so the new one will be called exchange public token like this and the clerk middleware stays the same and this stays the same so what we have to do now is the following we have to create a de-access token using await client item public token exchange like this and we have to pass in the public token and in here I'm just going to return okay true. So now we have to modify our params so that it accepts the public token. So let's go just below the clerk middleware and let's add z validator you can import that from hono zot validator so we are going to validate the json field which is going to be z from zod so make sure you've added the z import here z dot object and pass in the public token to be a z string and it's required like that. There we go. So now in here, we can destructure public token from C request valid JSON.
There we go. So we have the public token here. Perfect. So what I want to do for now is just return back the exchange. Let's go ahead and write it like this.
For now, right? We're going to modify this but let's do this for now. So now we have to create the equivalent hook here. So let's go inside of our hooks, my apologies, features, played, API and let's copy and paste use create link token and let's call this one use exchange public token so let me expand this so you can see use exchange public token and then inside of here we're going to use that so instead of create link token it's going to be exchange public token. We're still gonna use the 200 version here.
And now let's go ahead and let's create a type request type, the infer request type from Hono. So we bring back that import because here we have the body so we pass in again this exact line and we specify JSON so no need to specify 200 here because this is the infer request type. So we only care about the request here. And now add the request here and rename this to useExchangePublicToken. Inside of here we are also going to use the exchange public token but this time with JSON, right?
So we pass in JSON like this and this will be failed to exchange public token The success message will be public token exchanged. And we can copy and paste this error message here. Like this. And I'm going to go ahead and just import the back, the use query client. And we're going to add it here.
So const query client will be use query client. And I'm gonna go ahead inside of the on success here. I'm gonna add to do add, re-invalidate the following. So we're gonna re-invalidate the connected bank later when we add it. We're going to re-invalidate summary, transactions, accounts, and categories.
So I don't wanna do it now because I want you to understand why we are doing this. So for now I'm just going to leave it as to do. Great so that's what we're going to use query client for. For now it will stay unused. Great so we now have the useExchange public token which means we can go back inside of our PlayedConnect component where we use the usePlayedLink and let's add our exchange public token useExchangePublicToken and let's change this to useFeaturesPlaid and I'm going to move it here alongside our useCreateLinkToken Great, And now I want to go ahead and inside of this onSuccess, instead of console logging the public token, which we've confirmed now works, we're going to do exchange public token mutate and we're going to pass in the public token like this.
There we go. And let's also do the following. I'm going to go ahead and disable the button if this is currently pending. So I don't want the user to spam the requests. Great.
So we can try this out again now, but this time we should get back the actual access token. So I'm going to keep this open and more specifically I'm going to go inside of the network tab here. So I'm going to call the exchange here. So I filter out, so let's connect. Let's continue.
Select any bank. Go ahead and just pass through this select one account click continue accept the terms and connect and until you click continue nothing's gonna happen so when you click continue that's when there we go all right so we have an internal server error let's see what happened but at least we know that we are calling our endpoint here so let's see what went wrong here let's try and debug this all right converting circular structure to json starting an object with constructor client request. So I'm gonna go ahead and debug what exactly is going on here. All right, so I managed to get back a successful response and this was the culprit, at least I think. So I think it's because of the fact that inside of here, we tried to return the exchange like this.
I think this is perhaps too big of an object Or maybe we can't return back the Axios response for some reason. So let's do this. Let's do exchange.data and inside of here let's do access token. So let's try this out again. So I'm gonna go ahead and open this.
So I didn't change anything else, right? Everything else stayed exactly the same. Except of course this, right? Let's go ahead and try this again. So I'm going to prepare my network tab here.
Let's connect. Let's continue. Select a random bank. We select a random account here. We continue.
And we connect. Let's click continue. And there we go. Public token exchange, no errors at all. And here we have the access token.
So this is what we now have to store for our user in our database. So they never have to go through this process again, right? They should only have to connect to their database once and then we are going to handle everything else we want with Blade using that access token. Great! And if they want to disconnect, well all we have to do is remove that access token so that creates that functionality for us as well.
So for now the problem is we don't have anywhere to store that. So let's go inside of database, inside of schema here, and let's create a new field here, which we are going to call connected bank. So let's go ahead and go export const connected banks right here to be pg table connected banks is going to have the id is going to have a user id which will be text user underscore ID and is going to be required. And we're going to have an access token, which will be text access token like this and also required. There we go.
Let's go ahead and push that to our database so bun run database generate and bun run database migrate. There we go. Bun run dev and now let's go back inside of our blade right here where we currently just exchanged the public token and now we're going to modify this to see if we have an existing connected bank and then we're going to decide what to do next. So const connected bank is going to be await database so we need to import database let me just see where there we go. Database from DB drizzle right here.
Let me just go ahead and fix my OCD here. All right. So inside of here, we're gonna have database. Let's write it like this, database.insert inside of connected banks from database schema, values, user ID, alph.userID, access token, exchange.data.access token with an underscore and ID will be create ID from cuid2 so make sure you've added the createId service here. There we go.
Perfect. So we now have this and let's also add returning like this. There we go. So now this should take care of our connected bank. So let's see if that is true.
I'm going to go inside of the terminal, keep your app running and do bun run database studio here like this. Let's open this up. And right now, so ignore this fields that I have test, best and update. That is because I created an additional chapter to upgrade Drizzle. So I created this while I was testing, so no worries about that.
So just focus on the connected banks, which right now is completely empty. But if the user now goes through this process inside of their settings page, So let's just wait for this. Let's ensure that the link token is created and we can now click connect. Let's continue. Let's select the Chase Bank and let's continue here.
We are going through these things. Select at least one here, click continue and connect. And now if this is done successfully, there we go, public token exchanged. This should mean that no error was thrown and that if I refresh my connected banks, there we go. We have the access token with the matching user id stored.
Great, great job. So what we're going to do next is we're going to create the features and hooks for this connected bank so that we can now indicate to the user, hey you now have your bank connected and inside of this API endpoint we recreated the connected bank. We're also going to go ahead and create all the new categories, we're going to fetch the transactions and everything else. Great, great job.