Okay, so hopefully you gave that challenge a bit of a go.
It's relatively straightforward.
The challenge that I settled on in the end, compared to the original challenge that I was considering,
which didn't just involve using the function we have here or using this function, but making it the
same function also for the review component.
But the convoluted code we need to use to avoid using this kind of function as well.
When this is coming from our from our confirmation token for the shipping address and payment method,
preview the the types there kind of a little bit too different, especially not so much for the payment
method preview, but for the address string, we have to write some pretty convoluted TypeScript code
to make this function reusable across both our order types and the stripe types.
So I chose not to do this, and I'm just going to keep the review component as it is.
The one that we are going to focus on is the code from our Checkout Success page.
So I'm just going to cut these two methods from inside here, break the application in the short term
and paste them both into the util here.
And I'll export the const and change the name to Format and address string.
And I'll do similar for the payment one as well.
I'll export const and say format payment string, and just use the document formatter to line things
up a bit better.
And inside the format address string, all we really need to do is just take in the address as an argument
here.
So I will pass in address as the name of the argument.
And this is going to be of type shipping address.
And we get all kinds of warnings here because line one does not exist on type shipping address.
And where did I get that shipping address from?
Well, I got that from stripe.
Well, that's an error.
I actually want the shipping address from our own types because that's the type that we're using here.
So I need to get this from app models order.
And now our errors have gone away.
And then we can do similar fully format payment string.
I'll just specify card as that's what we're using in the return statement.
And then specify payment summary as the type.
And then I can remove this inside here.
And we don't get any warnings about we might not have the address because all of these have got the
optional chaining on.
Anyway.
We could check for the presence of the address and then remove the optional chaining.
But there's no need because this code is going to work just how we want it to anyway.
Then we can go back to our checkout success page and where we were using the payment string.
Here we can use our format payment string and we can pass in our order dot payment summary.
And then we can do similar for the address string here and just say format address string and pass in
the order dot shipping address.
And then in our order detail page we can make use of this.
We'll have instead of address goes here in curly brackets.
We'll use our format address string.
And just the same thing again we can use our order dot shipping address.
And then for the payment info we can use our format payment string and order dot payment summary as
its argument.
Nice and simple.
And if we go and take a look at our browser, we can see that we have both the shipping address and
the payment info populated inside there.
Now, now you might be wondering, it's like, hey, that's cheating.
We didn't do the tricky one.
Why didn't we do the tricky one?
Well, it's actually really tricky.
And I just want to highlight why it's tricky.
Because if we take a look at the address, this is the tricky one.
Then this shipping address is coming from a stripe type called payment intent.
Shipping and working with our own types is one thing, but working with someone else's types can be
tricky, especially from third party libraries.
And if I just right click and go to the definition to take me to the type information for lists, then
we can see that the shipping address property comes from another type called payment intent shipping.
So if I right click this one and go to its definition then we have a shipping interface.
Now the format of this is different to how we've defined the shipping address.
We've got the address actually as a property called address and it's of type address.
And we also have the name inside here that could be a string or it could be null.
And then we can go and take a look at the address definition.
And we've got our different address properties.
And these look familiar to what we've used in our code.
When it becomes really tricky is if I go back to the util folder, now that we've got that snippet of
information fresh inside our minds, and go back to our util, what we would need to use here for our
format address string, we would need to use a union type, for example.
And this would need to be of type.
The one that we just looked at would be of type payment intent.
And then in square brackets it would be shipping.
And then we get all sorts of problems inside here, because our return type is not going to match.
The only one that doesn't give us an error is the address name.
So then we need to start thinking about type guards.
And we could say okay fine, we know about type guards.
Now we could say if the address or if we're looking for an address.
For instance, when we were looking at this, we know that the payment intent shipping type has an address
as one of its properties.
So we could look for address in the address that we're using as an example.
And even then we get further problems because we don't know if this exists because of the type that
the payment intent shipping is using.
If we hover over this, then this could be null.
So then we need to before we even get to that stage, we need to check for the presence of the address.
And if we do not have the address then we return.
In this case I'll just demonstrate an empty string, but then we can start using the address properties.
So then we could say something like okay, now we know that this is going to be a type of payment intent
shipping address.
Because if I take a look at the let's see the address dot properties.
Now we've got the properties for the address dot address and we've got the name.
But what we'd end up doing is really just using a return statement inside here to then return a format
string based on the fact we're using this, and we'd end up with a similar amount of code to what we've
got anyway.
And it's just overcomplicating things because I know or we know, and maybe that will change in future
if we expanded this application.
The only place we're using that is inside this review component.
So I cheated a little bit by not going as far as I could do with this.
I'm not going to do it this way.
I'm just going to keep things simple inside this component.
And I didn't want to make this challenge overwhelmingly difficult because it can be if we go down this
approach of trying to make a union type out of this and then use type guards, I think simplicity and
clarity is preferable on a training course than ultimate conciseness of not repeating ourselves at every
step.
So now we've got our order detail page in place.
We've still got a disconnect between stripe and what we're doing from our checkout perspective, because
our order status inside here is pending, and the only way we can change that is by getting stripe to
notify our API that the order has been paid for.
And in order to do that, we need to start thinking about these things called webhooks.
And stripe can send an HTTP request to our API to notify our back end that the payment has been made,
because as far as payments are concerned, we don't communicate between our browser client and our own
API because we don't want to touch their payment card details.
That's communication directly between client and stripe.
So what we're going to take a look at next is we're going to take a look at webhooks.
And we're going to create an endpoint that stripe can use to notify our API that something has been
paid for.
And we'll take a look at that next.