Okay, so our next task is to create the payment intent when a user visits the checkout and every time
they visit the checkout, we want to update the payment intent because they could come to the checkout,
they could decide they want to continue shopping.
And when we've loaded the checkout initially we've gone ahead and created that payment intent.
But if they do update their basket, they'll have to come back to the checkout page if they do want
to pay for what they've added or removed from their basket.
And then we would need to update that payment intent again, so that the payment amount inside our intent
to pay matches what their basket currently is.
So every time they come to the checkout, we need them to effectively contact our API or make that request
to our API, which in turn is going to update stripe and update that payment intent.
So let's go back to VS code, and let's just clean things up at the top for the time being.
And we'll go into our checkout folder inside features.
and we will create a checkout API component or checkout API BTS.
And inside here we'll create this just like we have the others.
We'll specify export const checkout API equals create API.
And once again your friendly reminder to get the one from React or Redux toolkit query react I should
say.
And then we'll specify the reducer path and call it checkout API.
We'll use our base query and say base query with error handling and we'll specify the endpoints.
Add a colon, add the word builder and the arrow open parentheses.
Open curly brackets.
And then we can specify our queries.
So we're going to have a create payment intent Query.
So we'll use builder.
And this is going to be a mutation.
And we're going to get our basket back from our API.
And we don't need to provide this with any arguments.
So that will be void.
Then we open parentheses and curly brackets.
And then we can define the query.
So the query doesn't take any arguments.
For this.
We'll just use a function with no arguments.
And inside here we will return in curly brackets.
The URL is going to be payments and the method is going to be post.
And we need to update our basket.
And how do we do that using Redux Toolkit.
Because we do have a basket API.
And inside here our basket effectively is contained in the fetch basket query because it's cached.
And that's what we need to update here.
We need to update the cache if our API comes back with an updated basket with the payment intent ID
and the client secret.
So we effectively need to update this query.
So let's go back to our checkout API and take a look at how we can do that.
And once again we've used this a few times.
We're going to use the on query started I'm in completely the wrong place there.
I need to do this underneath the query.
So we're going to use the on query started.
And it's going to be an async method and doesn't take any arguments.
So we'll just use an underscore for the first parameter.
And then we need access to the dispatch and the query fulfill inside here.
And then we can add the arrow and open curly brackets.
And we'll do this inside a try catch block.
And if we get an error we'll just console dot log the error and say payment intent creation failed.
And add a colon.
And we'll just append on the error to the console log there and inside the try block we'll specify const
in curly brackets.
Data equals await and query fulfilled.
This should give us back our baskets inside this parameter because that's what our API is returning.
And then we can use dispatch.
Open parentheses.
And I'll move this down to a second line.
And we'll need to use our baskets API and the util from that.
And then we can use the update query data method.
Inside here we can use the fetch baskets.
The second parameter is the arguments.
That's going to be undefined.
And the third argument is going to be our draft basket.
So I'll use draft as the argument name.
Add the arrow open curly brackets and we'll use draft dot client secrets.
Equals data dot client secret.
And do we need the payment intent on our client side?
I'm going to say no because we will never use the payment intent ID on the client side.
So I'm just going to ignore the payment intent ID that I added.
I could clean up the basket type, but I'll just ignore it for the time being as it's not going to do
any harm.
But the only thing we really need inside our client side basket is the client secrets.
We've got the payment intents ID on the basket that's stored in our database.
We do need it there, because that's what we're going to use to update a payment intent.
But as far as our client goes, then all it needs is the client secret here.
So that will suffice for our query.
And then we can go to our stores as we need to update this as well.
And we'll add in our checkout Out API reducer path and say check out API reducer inside here, just
as we've done before.
And we'll also add the middleware as well.
And like so and I need to go back to the checkout API because we do need to export the hook from here
as well.
So we'll use exports const and inside curly brackets.
I'm just going to or add the curly brackets then use the checkout API.
So I get the auto completion help.
And we need to use the use create payment intent mutation from this.
So then we can go back to our checkout page and make use of what we've done here.
And when the checkout page loads then we're going to need to call our use create payment Intent mutation.
So we're going to need to do this inside a use effect.
And we'll use const.
and will bring in the function first.
And I'll just call it create payment intents.
And I'll also bring in the is loading here from this hook as well.
And say equals use create payment intent mutation.
And we'll use a use effect inside here we'll add the callback function and we'll add its dependencies.
Now for this one I'm going to take extra extra care, especially whilst we're in development mode now.
We haven't been affected by it so far because of our usage of RTK query.
But whilst in development mode, whilst in strict mode, then a use effect would typically be executed
twice.
Now I do not want this function to be executed twice just because I'm in development mode.
I would like to prevent that kind of behaviour and one way that we can prevent that kind of behavior
is to add an extra hook inside here.
And I'm going to say const created equals use ref.
And I'm going to specify false as its initial value.
So this use ref.
It's effectively a mutable object whose current property is initialized to the passed argument, which
is going to be false, and the returned object will persist for the full lifetime of the component.
So it's unaffected by our checkout page Rerendering.
For whatever reason, the value of this persists.
So we can use this to effectively check to see if this has been created.
The payment intent has been created when this component has first loaded.
So the way that this works is I'm going to check to see if not created dot current or not.
And I meant to call that created.
So I'll specify created currents.
Then we will create the payment intents.
And after that has been created we'll update created currents to be true.
So the next time this use effect is called then created is going to be set to true, which means this
method will not be executed and we will not create an additional payment intent.
In testing I was able to onloading the checkout.
I would actually consequence of this, or the consequence of this would be that an additional payment
intent was created in stripe, and then we would have two payment intents for the same baskets, which
is not ideal.
So this avoids that kind of scenario in production.
This is not relevant because it's only going to be executed once anyway.
This is more of a development trick that we need if we want to avoid An external service, being updated
twice when we don't want it to, and our dependency for this one we've got the warning here tells us
we need to add the create payment intent as a dependency, and I'll use the Isloading here as an additional
check before we load our checkout stepper.
So we'll also add another or condition and just check to see if we're loading in this case.
So let's go back to our browser and see what kind of progress we've made.
Well I can see that the checkout has now loaded.
That means that our basket now has that client secret.
And if we go and inspect and we'll ignore the console, we'll just go straight to our Redux DevTools
in this case.
And we take a look at the latest state.
And we take a look at the basket API inside the queries inside the fetch basket and take a look at the
data.
Then we can see that we have the client secrets available and that is what we would expect, what we
would also expect depending on the items we have in here, I've got a product ID of ten which is priced
at 1800, and I have a quantity of one.
What we would also expect is that this transaction to be reflected inside stripe as well.
So if I just refresh this page, then what we should have is another payment intent.
And that's correct.
It's $18 for the item.
And because it's below $100 then we've got the plus five delivery charge there as well.
So excellent.
That's what we'd expect.
And that should also of course reflect in our order summary on the right hand side.
So great.
And our next step is going to be the address step.
And we'll take a look at what we need to do for that next.