تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Order API Overview0:05

A little webshop application is coming along nicely, but it's missing the most important feature of all actually being able to place an order. Let's go ahead and build this functionality together. I already provided two more API calls. We can do a GET request to orders and we can do a POST request to orders and both of these API calls live within our route group that need our out header to be present. If you dive into the OrderController class

that need our out header to be present. If you dive into the OrderController class and we take a look at the index function, we can see that we simply return all the orders on the currently authenticated user. We load the orderLines and we return it using our OrderResource. If we take a look at our User model, I defined a relationship so a User has many orders and if we dive deeper to the Order,

I defined a relationship so a User has many Orders and if we dive deeper to the Order, an Order has many OrderLines and in the OrderLine we do the inverse, we can say an OrderLine belongs to an Order. If you briefly take a look at the database schema, we have an Order table with a foreign key to the User. We have a decimal for the total price and we have a decimal for the tax rate. Then on the OrderLines, we have a foreign key.

Order Creation Logic1:09

and we have a decimal for the taxRate. Then on the orderLines, we have a foreign key to the order we store the title, the quantity, the pricePerUnit, and the totalPrice of the product. Going back to the OrderController, let's take a look at our store function in here. We'll first validate that every product we get in the request actually exists in the database and we filter out the ones that don't.

actually exists in the database and we filter out the ones that don't. Next we'll map the cart items in a simple object that includes the database product, the quantity, the price per unit, and the totalPrice. Then we'll create the order on the current User. We'll save the textRate and we'll calculate the totalPrice. And finally, we'll loop over our cart items and will create the orderLine on the newly created order,

Testing Orders API1:49

And finally, we'll loop over our cart items and will create the order line. On the newly created Order, we will store the title, the quantity, the price per unit, and the total price. Finally, we'll load the orderLines relationship and we'll return an OrderResource of the newly created Order. Let's quickly see the API in action. So let's first create an Order. So we'll do a POST request to api/orders.

So let's first create an Order. So we'll do a push request to API orders. We'll send our cart, which is an array of object that's contained an ID and a quantity. And if we execute a request, we'll see the order has been created with two order lines. We have our pizza, and in here we have our burger. Now let's say we add an invalid ID in the cart and if we create that order, we'll see we only created the pizza.

Building Orders Store2:32

and if we create that order, we'll see we only created the pizza. Next, if we do a GET request to API orders, we'll get a list of all the orders that have been placed by the current user. Let's integrate this in our app. Let's start by creating our order store and by now they should feel pretty familiar. Let's say export const orders, store equals definedStore, and let's make this an optionStore again.

Use orders, store equals defined store, and let's make this an option store again. But first, let's import the findStore from Pina and let's add an action that's called confirmOrder. It'll get a card parameter and in here we'll do our logic in our checkout page where we'll confirm the order. Let's get rid of this and let's say conResponse equals cardStore.convert.

and let's say $con response equals CardStore::convert. Now in the CardStore, let's create our convert function. I remember because this is a setup store, we have to export it here And inside our convert action, let's say use OrderStore::confirmOrder $cardValue. Now let's jump back to our OrderStore and let's create our API layer. And in my case, the API lives on

and let's create our API layer. And in my case, the API lives on viewStateManagement backend. Do tests/api/orders. That's import Monday and Incon confirm order. Let's get rid of our comment and will say return orders post. And in here we'll say card and let's say card.map item. And we actually only need a productId and a quantity. So we'll say return products.id,

And we actually only need a productId and a quantity. So we'll say return productId, itemId and itemQuantity. And let's test this out. Let's click confirm order and we get a 401 Unauthorized error. Now this actually makes sense because remember the API expects a Bearer token that we aren't sending yet.

Global Auth Header Setup4:33

because remember the API expects a better token that we aren't sending yet. Now if you take a look in our user store on our fetchUser action, we actually already created an authenticated API request where we send the Authorization header, which is a better token. With the token, we got the authentication data lives in our user store and lucky for us, Monday allows us to set things like headers globally.

and lucky for us, Monday allows us to set things like headers globally. So inside our fetchUser we can get rid of the headers we pass. Let's go to setToken. And if we have a token, we can say defaults.headers.authorization equals Bearer token. And if you don't have a token, we can actually say delete defaults.headers.authorization as follows.

we can actually say delete default Heather. Authorization as follows. And default is actually an export of mandate. So if you go up, you can say import mandate default from 'Monday'. Now if you refresh, the application should still work as before. And if we dive into our User API call, we should see the headers. Let's make this a bit bigger.

we should see the headers. Let's make this a bit bigger. We should see the authorization header is still being sent correctly, which is great. Now when we confirm our order, we get a 500 error and that's because I made a mistake, I should say id instead of product_id. Now when we press confirm order and we take a look at the headers that we send, we send our authorization bearer header

and we take a look at the headers that we send, we send our authorization bearer header and we get our data back. So our Order has been successfully created and even though we don't explicitly send our authorization headers in the API call Monday, we'll apply the authorization header because we put it on the default, which is pretty neat. Now after placing the order, let's redirect to a thank you page.

Post-Checkout UX Updates6:08

Now after placing the order, let's redirect to a thank you page. So if you go to router, do js, I created a thank you page, which takes an orderId as a name, thankYou, and it'll render the component. Thank you. So in here we can say router.push name thankYou orderId, responseId and let's jump into our cardStore.js. Let's do some changes. First it's gonna be an async function.

Let's do some changes. First it's gonna be an async function and let's say const returnValue equals await confirmOrder and let's return the returnValue. And in confirmOrder, let's await the result as well. And let's make it an async handler. And after a response we can say router.push, we'll say name. Thank you. I will say parseOrderId, response.data.id.

Thank you. I will say parseOrderId, response of dataId. If all went well, I we press confirmOrder. You'll be redirected to a thank you page and we can see the URL is thankYou with the orderId. Now where we go back home, we'll see our cart isn't cleared, so let's fix that. Now if we jump into our cart store, we'll say clearCart. And now when we confirm an order and we go back home, we'll see our cart is cleared.

And now when we confirm an order and we go back home, we'll see our card is cleared. Neat. Alright, so now this is looking pretty good, but what happens when we're logged out? Well, let's test that. Let's log out, let's put something in the cart. Let's go to the checkout page. Press confirm order, nothing happens. And if you take a look in the console, we get our unauthorized error again.

Protecting Checkout Route7:39

And if you take a look in the console, we get our unauthorized error again because placing orders requires us to be authenticated. Let's also apply the login middleware we created in the previous lesson to our checkout page and we can do so as follows. Let's go to the routes. We can copy our meta here. Let's go to the checkout route, paste our meta, and now when we go to the checkout page, we'll be prompted to log in, which we can do,

Displaying Order History8:03

Paste our meta, and now when we go to the checkout page, we'll be prompted to log in, which we can do, and then we'll be redirected to the checkout page and we can confirm our order. And this worked out of the box. Look at that. Next up, let's add our order history on the profile page, let's open profile.view. And in here, let's fetch the orders. When the component mounts, we'll say onMounted orders, store fetchOrders, let's create our orderStore.

When the component mounts, we'll say on mounted fetchOrders, store fetchOrders, let's create our orderStore and let's import it. There we go. Now let's create our fetchOrders action. So we'll say fetchOrders and we need to create a state. We'll initialize it to an empty A and interaction. We'll say const response equals await orders.get using our API layer that made this asynchronous. And then we can say this.orders equals response.data. If we take a look at the network tab, we'll see

And then we can say this $orders equals $response data. If we take a look at the network tab, we'll see our orders API call with the data being returned. And remember from last lesson, we can also go to the dev tools. Pia, we can go to orders and you can see the order state is getting filled up, which is great in the profile view. We can loop over the orders. Let's first take this, wrap it in a grid.

We can loop over the orders. Let's first take this, wrap it in a grid. Let's create a grid of 12 columns. Then we can say class call span four, and let's paste and let's create call span eight. And in here we'll loop over all the orders and render an order card. We'll say v-for orders in orders, store orders. And if you take a look at the order card, we have a required prop called order.

And if you take a look at the OrderCard, we have a required prop called order. So let's pause that in. And there we go. And let's apply some more styles. Let's say flex, flex-col and space-y-3. And look at that. Where we refresh the page, we have a nice OrderHistory. Let's dive into the OrderCard and let's see how it's built quickly. So we have order, we display

and let's see how it's built quickly. So we have order, we display our order id, we display our total price. We loop over every item in the orderLine. We'll say the quantity times the title. We will display a formatted unitPrice. And finally we'll display our formatted total price. While we're here, I noticed the card overlay doesn't open on the profile page, which actually makes sense because the component is rendered inside of our homepage.

Cart Overlay Store Refactor10:37

the profile page, which actually makes sense because the component is rendered inside of our homepage. So let's go into the Home component. Let's ying the CartOverlay out. Let's go to app and we can paste it here and we can actually get rid of the open prop and the close handler. And if you dive into the CartOverlay, we can get rid of the props. And now let's create a dedicated store

we can get rid of the props. And now let's create a dedicated store that will manage the open state of the cart overlay. Let's create cartOverlayStore.js. We'll say export const useCartOverlayStore equals defineStore cartOverlay. Let's create an option store. Let's say state return, visible, false, and then we'll have an action that's called toggle.

false, and then we'll have an action that's called toggle. Let's say this visible equals the opposite of the current state. Let's create open where visible is set to true, and let's create close where this visible equals false. Let's not forget to import, define store from pia. Then in the card overlay, we can go to the script tag and we'll say import use card overlay store, let's say const card overlay store equals use card overlay store.

and we'll say import useCardOverlayStore, let's say cons, cardOverlayStore equals useCardOverlayStore. And then let's go to the template and let's replace open with cardOverlayStore.visible. When we'll emit close, let's quickly do a replace. I will say cardOverlayStore.close, and let's see if we have something else to change. That should be it. Let's go to the nav bar. And in here we have a button with our shopping cart icon

That should be it. Let's go to the nav bar. And in here we have a button with our shopping cart icon that will emit cardClicked. We can say cardOverlay, storeOpen, let's create our cardOverlaysStore. Don't forget to import it. And now when we click on the card icon, it should still open and close as before, so we can also click outside. That still works. And when we go to the profile page, the cardOverlay now also works great.

Navbar Branding and Recap12:59

That still works. And when we go to the profile page, the card overlay now also works great. Another thing that's been bugging me for a few lessons is that I forgot to add a name in the nav bar. So let's do that now. So at the top we can say div, Let's give the class flex and items center. Let's add a router link to the route, and let's call it Acme store. And let's actually copy the styles of our login button. Let's do this. And there we go. And let's make it bold.

And let's actually copy the styles of our login button. Let's do this. And there we go. And let's make it bold. And there we have it. Our web shop now looks great and it has order functionality before moving on to the next lesson. Here's a quick recap of what we did. We created an OrderStore that's responsible for communicating with the API to retrieve and to place orders. Because the orders endpoint in the API

to retrieve and to place orders. Because the orders endpoint in the API requires authentication. We had to update Monday to store the authentication token globally. Whenever we sign in, we put a checkout page behind our login middleware, so we require the User to log in before checking out. Finally, we display the orders on the order page by fetching them through an action on our order store.

Finally, we display the orders on the order page by fetching them through an action on our order store whenever we go to the profile page. And along the way, we made a few changes to our application, like allowing the cart overlay to be open from any page by giving it its own store. Let's move on to the next lesson.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟