How to build an eCommerce Website using React Redux, GraphQL, Firebase #21 – Order History

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to the 21st video in this video series on building an ecommerce website using react redux graphql and firebase in today's video we're going to be working on our order history so let's take a look at how this works and i've already added a few items to my cart so i'm just going to go ahead and click on my cart as you can see i can make some changes to it but i'm more or less happy so i'm going to go ahead and click on check out okay so i've skipped ahead i've entered in my shipping and billing information i'm going to go ahead and enter my card number again i'm using stripes payments api but also i'm using a test api so i can just put in my test card number and click on pay i'm then going to be taken to my order history page i can see previous orders that i've made and i can select i can click on either one of them when i do i'm taking to my order his my order details page where i can view both not only the order id my my order number i can view the total amount i can view the individual products that i purchased the price and quantity of each of those items as well before we get started i want to encourage you guys to check out my official youtube channel that's youtube.com forward slash simpletut not only to watch my other videos but also to find the official playlist for this series i'll be posting a direct link to this in the description of this video but i also want to send you guys to the official github repository for this project again there'll be a link in the description of the video but as always please like comment and subscribe and don't forget to turn on those notifications we're going to be using redux to handle our order history so there's a few new files that we need to create in our redux folder i'm going to store these in a folder called orders and the files i need to create are going to be orders dot types we need orders dot actions dot js orders dot reducer dot js orders dot sagas dot js and finally our helpers so orders dot helpers dot js now the first thing i'm going to do is i'm going to define the types that we're going to be using so thinking ahead we need three new types but before i tell you what those are we need to create a const to store them in so we'll say const order orders types it's going to equal an object we need to remember to export that so we're going to export our order types now the types that we need to create first of all is going to be um save order history start right and the value of that is going to be the same as the name of the key we're going to use this we're going to dispatch this to actually save our order history to save our new order to the collection on our firestore we need another one to get user order history right and we're going to start and again the the the value is going to be the same as the name assigned to the key and then finally we need another one to um set user order history and we're going to use this when we've actually fetched a user's order history and we're going to use that to actually set that data in our redux store the next thing that we need to do is create our actions so i'm going to come into my orders actions file and we're going to import our types so this orders types from our types file so orders.js and then we need to create those corresponding actions and the first one is going to be the our save action so i'm going to export const i'm going to call this save order history and it's just going to take an order and then it's going to return a object with a type type is going to be order types dot save order history start and the payload is going to be the order and then we need to create another action to get a user's order history so again we're going to export const get user order history it's going to take a uid of the user and again it's going to have a type and payload so the type is going to be orders types dot get user order history start and the payload is going to be the uid and then finally we need another one to set the history in the redux store so we're going to export const set user order history and again that's going to take some some history and then it's going to return an object with a type and payload the type is going to be order types dot set user order history and the payload is going to be the history and i'm going to save those changes now that we've written our actions we're ready to actually create our sagas so let's come into our orders.sagas and we're going to use this to actually handle our async code this is when we are actually going to either set or fetch data from our firestore and then pass that into our redux store so to do that we need to import first of all our types so i'm going to say import orders types we're going to import that from our types file so it's going to be orders.types we're also going to need to import some things from redux saga itself so we'll say redux saga here slash effects and the effects that we're going to need to import are going to be take latest put all and call all right so we're now ready to write those generator functions and our sagas so what we're going to do is we'll say export function and as it's a generator function we need to put an asterisk after the function keyword and then we can actually just say on this is the name of our generator function and of course within redux saga we have this naming convention of using the the on prefix right so it's going to be on save order history start right and what we're going to do here is we're going to yield take latest right and this expects two things first of all the type that we want to listen and intercept right within our redux store so we'll say order types dot save order history because that's the action that we want to intercept and then we need to pass the name of the generator function we'll use to handle this this event so we need to create that so we're going to say export function again it's a generator function we're just going to call this save order it's going to receive the entire um action right so that includes the payload which we're going to destructure and in this case that's going to contain the order and we're going to handle that within these within these braces here right but we're going to come back to that for now it's going to be enough for us just to pass that in to take latest right so that's actually the boilerplate code done but we do need to export this at the bottom of the file and then we need to pass that to our root saga so that our redux store is actually aware of this file because it is a new file so to do that we need to export this at the bottom of the file so we're going to export default function which is again it's a generator function we're going to call this our orders sagas and what we're going to do is we're going to call yield all we're going to pass in an array where we're going where we're going to call those initial generator functions right so the one that we created here which is on save order history start we're going to pass that in here and we're going to save those changes and let's just add in um let's just add in a line break at the bottom of the file and then what we can do is we can come over to our root saga and what we can do is just import that file right so we're going to say it's our orders sagas we're going to import that from the file itself so we'll just go into order slash orders sagas and then here we can pass that in right so we'll say call our orders our orders sagas and we can save that and that's just making uh it's it's going to pass it to our redux store and it's going to make our redux store aware of these sagas so it's going to enter be able to intercept this action uh every single time that it gets dispatched okay so we're now ready to write out our save order generator function uh this is where we're gonna actually handle our async code um so what we're gonna do is we're gonna put this within a try catch so we'll say try we're gonna catch any errors right and then what we can do here if we get an error is we can just you know console log the error or we could pass that back to the front end but for now i'm just gonna comment that out and here what we really want to do is we want to perform this this action right so i'm actually going to use a helper function which i'm going to define here so let's come into our orders dot helpers file and first of all we need to import a util that we created at the start of this series uh which i'm exporting from firebase slash utils which is our firestore right so if i come into this file again we created this in one of the first videos in this series and one of the things i'm doing in this file is exporting the firestore right so that's just a helpful util we've used it already in a number of places and we're using it again here you'll see how in just a second now we're going to export this helper function so we're going to say export const handle save order right and this again is just going to take an order and then it's going to what it's going to do is it's going to return a new promise right and as it's a promise we're going to get resolve and we're going to hit reject and then what we can do here is we can call firebase sorry firestore and we can chain on a bunch of methods here right so the first one is going to be our collection so we're going to target our orders collection and of course if orders co if our orders collection doesn't exist it's going to create it if it does exist we're going to just use that collection and then we're going to create a new document so we're going to say doc and then we're going to call this set method and we're just going to set the order right uh and what that will then allow us to do is call the then method right we'll say then um and if this is successful we're going to resolve this promise which means it it was successful however if we catch an error what we're going to do is we're going to get the error right and we're going to call reject and we're going to pass the error back to the front end right so now that we've defined our helper function we can come back over to our saga and we're going to import that helper function so we'll import that helper so we'll import that from orders.helpers we need to import handle save order and then we can yield that right so we can call yields handle save order call that and i'm going to pass in an object here and i'm going to use the spread operator to pass in the uh object here for our our payload now the reason that i'm i'm i'm passing this using the spread operator is because i want to to add a few uh i need to add some additional data here so the first thing is the order user id right so this is going to be the id of the user uh that has created this order so to get that we need to import something uh we need to import something from again our firebase utility file so firebase utils which is auth right so what we can actually do is we can call auth dot we can call auth dot current user dot uid and this will just allow us to fetch individual users order history because otherwise there would be no way to associate an order with an individual user which is something that we will need to do and then finally we'll need a way of ordering this on the front end so i'm going to call i'm going to add on here order created date right and just above this here i'm going to create a const called timestamp right and i'm just going to say new date dot uh to date string and i'm then going to pass that in here as well okay so at this point we are ready to actually save orders so we can actually go to the front end and dispatch this action so to do that let's come over to our components folder and we need to find our payment details component which is here and as you can see right now what we're doing is we are once a payment has been successful we're dispatching our clear card action which we're using to empty the user's cart because they've now checked out and then we're redirecting them away i believe to the home page now what we want to do is we want to dispatch a new action which is our safe order history so that once a user has successfully processed the payment and checked out we're going to save that to their order history and we need to dispatch that here right so let's delete this and what i'm going to do first of all is i'm just going to come up to the top and i'm going to import the action we just created so we need to import that from our redux folder so it's redux slash orders slash um our orders actions and it is our safe order history action right so what we can do is we can then come down right and first of all we need to find our our code here there we go so where we were previously dispatching clear cart we now want to dispatch uh our new action which is save order history right but as you'll know this expects an order right we need to pass an order which is the object we want to save to our collection so i'm going to build that object so i'm going to say const config order right and what i'm going to do first of all is i want to specify the order total right so i'm going to say order total and that is going to equal total so we already have access to this we're getting that here from our use selector hook we're getting that we have our custom selector here so that's fine now i also want to pass in the order items right because usually when you look at order history you can see the order total and you can see the items that were purchased within the order so we're going to say here order items right now now unfortunately we don't currently have access to the order items or the cart items within this component so we're going to import another selector that we wrote in a previous tutorial which is select card items right and then within create structured selector here in our map state function what we're going to do is we're going to add in cart items right and pass it our select cart items selector here let's save that we also need to then get access to that we can do that here where we call our use selector hook to get access to our cart items but of course our cart items right we don't want to just pass in our cart items because unfortunately this contains a lot of data that really uh is unnecessary we don't need to store all of that data we only need a a a a a few fields of it right so what i'm going to do is i'm going to call the map function on cart items we're going to get the item right and then what we want to do is destructure the fields we want from the item right so we'll call d structure from item and the first thing we want is the document id right we want the product thumbnail we want the product name we'll get the product price and the quantity okay so once we have that we're then going to return only those fields so again the document id the product thumbnail the product name [Music] the product price and the quantity right let's save those changes and then where we dispatch our save order history action we're just going to pass in our config order right so that looks much better but of course at the moment once this has been dispatched let's look at what's happening here if i come up a little bit you'll see we have this use effect hook right which is checking the item count is less than one which means that basically their cart has been cleared and then we were redirecting them to the home page now what we want to do is we actually want to redirect them to their order history which i can tell you now is going to be our dashboard so i'm just going to now change this to be redirecting users to our dashboard right but unfortunately previously we were just we were dispatching our clear cart action within this component right but now we are dispatching our safe order history action so we are no longer clearing the cart after a user has successfully checked out so what we're going to do is we're actually now going to dispatch that action from our saga right so once we have saved a user's order history successfully we're going to dispatch our clear cart action so to do that we're going to import that action in this file so to do that we'll come out of this folder we'll go into cart and our cart actions we want to import our clear cart action and then all we have to do is call yield put and just dispatch clear cart okay so we're almost ready to test this in the browser i just want to make a small refactor here so on my orders saga when i create my timestamp i shouldn't actually be creating a string here we do want this to be a normal timestamp so i'm just going to make that small change save that and we're now ready to test this in the browser so i've gone ahead and i've added a few items to my cart i've clicked through to my checkout page and i've already entered my shipping and billing information i'm going to go ahead and enter my card details again i'm using the stripe development api keys so i can actually just enter a test card here and then i'm going to go ahead and click on pay now and what you should see is i'm going to get direct redirected to my dashboard and as you can see if i come into my firestore and as you can see i now have my orders collection with an order and as you can see you can see all the information about the order that we created right so we have our created date which is our timestamp we have our order items okay so at this point we're ready to actually fetch this on the front end so that we can actually show the a user's order history in the browser okay so we want to actually show a user's order history on their dashboard within their account which is going to be on this page but of course we can only do that if we go out and fetch the data first so we need to make a start by actually coming back over to our text editor and i'm going to go ahead and i'm going to close all the other files because the file that we want to start off with is our sagas so earlier in the tutorial we already created our action which is our get user order history action we're also going to use our set user order history but we need to first of all just go ahead and create our sagas right so i'm just going to scroll down the file here or maybe i'll do it at the top add in a few line breaks to make it a bit easier to follow but what we're going to create first of all we're going to create export function it's a generator function and we're going to call this on get user order history start right and just like before right so we're going to call yield take latest it's going to take the type that we want to intercept so this is going to be get user order history start and again we need to pass in the name of the generator function that's going to handle this async code so we're going to say export function generator function we're just going to call this get user order history this is going to we're going to destructure the payload and then we're going to be able to handle that um handle that logic within these these braces right but we're going to need to first of all pass this into take latest but we're also going to need to export this at the bottom of the file so we're going to export on get user order history start we're going to export that here so that we're going to pass this on to our root saga so here we'll just pass that in and that means that we're passing this to our root saga and that is going to pass it to our redux store so that it starts listening for this this action when it gets dispatched so it can intercept it and it can call this generator function which is where we're going to call our try catch and handle our async code so again we're going to have another try catch here we're going to catch any errors and again for now i'll just console log out the error but i'm going to comment that out for now but what we need to do here is we need to actually call another helper function that's actually going to be the one responsible for fetching a user's order history from the store the only thing that's important to be aware of here is what this payload actually is going to contain so if you look at the action here that's getting dispatched which is this one the payload is actually equal to the user's uid so we're passing in the user's user id here and we're going to pass that to a helper function we haven't written the helper function yet we're going to need to do that now so what we'll do is underneath this what we'll do is we'll say export const handle get user order history it's going to get a user's uid and then again what we're going to do is we're going to we're going to return a new promise right and that is going to get resolve and reject and we already have access to our firestore and i misspelled return here now we already have access to firestore but we're going to do this a little bit differently right so what i'm actually going to do i'll just scroll a little bit here create a few line space i'm going to store a reference uh to my firestore collection in a variable which i'm going to assign to let so what i'll do here is i'll say let ref equals firestore we're going to target the collection our orders collection so we'll say orders and we also want to chain on order by and if i come back over here to my sagas and i look at my save order generator function here you'll see that we have order created date and this is what we want to order our uh our order history on right but what we're gonna do here is we're gonna can we're gonna add on a condition right here so we're gonna say ref equals our ref dot where and what we want to do is we want to filter the collection right but we only want to get the order history of a particular user so again if we reference our saga we have our order user id that we can use because that contains the user's uid so we can compare these two so what i'm going to do is i'm going to say where the order user id right is equal to the uid that we are passing into our helper function okay so what we can now do is fairly straightforward we can just call the ref and we can again we can just chain on here dot get that's going to get us that's going to get a snapshot we can then say then right call then and again that's going to get our snapshot so we'll just say snapshot we'll just call it snap um and then what i want to do here is it's only going to contain a reference document right so we need to get that so i'm going to store that in a const i'm going to call this data okay and what we'll do is we'll use the spread operator we're going to call snap dot docs dot map right we're going to get the individual document we're going to return an object again we're going to use the spread operator right and we're going to call doc dot data we're going to call that method and that's going to get the data on the ref on the on the document but it's not going to return the document id which we are going to need for our order details page so we're going to again we're going to add in our document id right which is going to equal the doc dot id and then what i'm going to be able to do here is i'm going to resolve this right but what i'm going to do is i'm going to pass in data now if there was an error just like before what we can do is we can say dot catch we can get the error and we can call reject and pass it the error but that's actually all we need to do for our helper function here to get a user's order history i'm just going to add a semicolon there and a line break at the end of the file so we can now come back over to our saga we can assign this to a variable i'm going to say const history here it's going to equal yield we're going to yield and await the response from our helper function here which we need to import so up here where we import our helper here for handle save order we're also going to import our helper function for handle get user order history so we can call that here and all we need to do is pass in our payload which is our user's uid right and then once we have that assuming that it's successful because if it wasn't it would fall into the catch so as long as it hits this line we know it's been successful what we can do is we can dispatch another action right which is to set our history in our redux store so at the moment we're not importing it but we do have another action here which is set user order history so we need to import that from from our actions file so we're going to import from our orders actions and we're going to import set set user order history so we'll we'll call yield put and we will dispatch our action and we'll pass it our history which if we look at the action is exactly what this expects okay so at this point we're fetching our user's order history and we're dispatching an action to actually set that in our redux store but we don't have a reducer currently set up to actually handle this action so we need to come over to our orders reducer.js and the first thing we'll do is just import our types so we'll say orders types we want to import that from our our types file here and we need to create our reducer so let's do the boilerplate code so we'll say const orders orders reducer it's going to equal a function right that's going to take some state we're going to by default pause it some initial state which we haven't defined so we'll say cons initial state and we're going to pass that here by default and it's also going to receive an action and the initial state is just going to have some order history which is by default it's going to be an empty array now this is going to be a switch function so it'll be a switch we're going to pause the switch function the action type right and it's going to have a default case where we just return the state and we need to remember to export this by default at the bottom of the file so we'll say export order orders reducer and then we just need to define our case here so we'll have case orders types dot set user order history where we will return the state but we will set the order history to be the action dot payload just like we did with our saga we need to pass our reducer to our root reducer so let's come over to our root reducer here and we need to import that file so we'll say import our orders reducer we want to import that from the file so it's slash orders slash our orders reducer and then here we'll just say our orders data and posit our orders reducer okay so what i want to do now is i want to utilize the actions that we just created so that we can actually fetch a user's order history and then pass that into a component that can consume the data and render out the user's order history within the ui so to do that let's come back over to our our code editor and we want to go into our source and pages and our dashboard index.js so the first thing that we need to do is we need to import the use effect react hook we also need to import some things from react redux which will allow us to dispatch our action and also get data from our redux store so we'll need use dispatch and use selector and we also need the action that we just created so we'll import that from our redux folder so we'll go into redux slash orders slash orders actions and the action we need is the get user order history action and then what we need to do is first of all get access access to dispatch so we'll say const dispatch equals use dispatch and call that hook and then what we'll do is we'll call the use effect hook here which of course takes a function and a dependency array the dependency array is going to be empty because we only want to run this on the initial page load when this component mounts so we'll all we're going to do here is actually just dispatch our action to go out and fetch our users order history but as you know this expects the user's user id right that's how we get only a specific user's order history so we need to get the current user from a redux store we have that already in our redux store so we'll call we'll define map state right which is going to we're going to destructure the uh the user from our redux store here and what we want to get is the current user we'll get that from user.current user and then what we can do here is we can call our use selector hook and pass in our map state here and what we'll do is we will get our current and then we will pass that in here with the id of the user right so at this point we are successfully fetching the user's order history and we are adding that into our redux store okay so at this point we have successfully dispatched the action to go out and fetch a user's order history from firebase and then store that within our redux store but what i want to do is i just want to come over to the browser and show you that currently if you visit your dashboard which is where we dispatch our action you're going to see that we are not seeing our order history all right so our redux store is actually still empty um but there's no errors here we're not really seeing anything so what i'm going to do is i'm going to come back over to my code editor i'm going to come over to my orders saga and within the generator function for get user order history i'm going to uncomment out the error right so we're now logging the console error within the try catch i'll come back over to the browser right and i'm going to navigate back to my account page and you're going to see that the error we're getting is that it actually is telling us we need to create a new index within our firebase database right now the reason we need to create an index is because if we look at our helper function we're performing an order by and we are also calling the where method right now to perform a more complex query like this we're going to need to create a new index now this is something we've also done before when we were looking at our product results pages but on this occasion all we have to do is simply click the link that firebase provides for us if i go ahead and click that it's going to prompt me to create a new index all i have to do is select create index and although it is going to take a little bit of time it is going to create the index for me and at the moment you can see it says it's building but once it switches to enabled this will be ready to go and we'll be able to test this again in the browser and we should start seeing uh results okay so you can now see that this is enabled so if i come back over to the web browser you'll see that uh in my redux store i now have already gone out and fetched the user's order history and this is the order that we created moments ago what we're now going to do is we're going to consume that data on the front end right so we're going to build a component that can actually take the user's order history and then render that out as you can see here i'm going to be using material ui this is a really cool ui library from google i'm quite sure you will have heard of it but we are going to need to install this what we're going to be using is some of the pre-built components that they provide for creating really nice looking tables and it just makes it a lot easier for us to use but it's also something that's useful for you to be aware of for other projects in other areas of even this application it is very useful so before we can use it we need to install it so i'm going to grab this line here to install you can either copy it you can come to the website yourself which is material ui.com or i'll post a direct link in the description of the video so let's come back over to our text editor i'm going to go to terminal new terminal and i'm just going to go ahead and install this so i'll paste in that line and hit return and that's going to go ahead and install material ui now we are also going to be installing moment.js this is another really cool uh library that we're going to be using to actually render out our date right so with order history we want to display the order the uh the order created date and as you know we stored that as a timestamp so to format that correctly on the front end we're going to use moment which is a really cool library just for handling dates and time stamps so i'm going to grab that as well so let's come back over to the text editor and again i'm going to install moment so npm install moment okay so at this point we're ready to actually go ahead and create our order history component this is the the component that's going to consume the data from our redux store and then render out the user's order history in the browser so the first thing that we need to do is go into our source folder components and we need to create a new for a new file we're going to call this order history slash index.js right now this is going to be a functional component so we're going to import react from react right it's a functional component so we'll just say const order history it's going to receive orders as a prop and we'll have a return here we'll come back to that first of all let's just export this by default so we'll export our order history and what we want to return is actually from material ui right so let's import those components so we'll import from our library so it's material ui core the components that we need are the table components so the first one is our table container then we need our table we need a table head and a table row we need a we need the table body and the table cell right so those are the components that we're going to be using then what we need to do is just render that out right so just imagining how this would flow naturally so you have your table container with your table inside right and then you're going to have your table head and then below that you're going to have your table body within your head we're going to have a table row but within our table row what we're going to do is we're going to first of all define our columns so the columns are the fields that we want to display from our data so we're going to say const columns right which is just going to be an array of objects with an id and a label the id is the field that we're getting from the data so in this case the first one will be the order created date and we're going to render this out as the order date you can actually label this anything you want the second one will be the uh the order id which is actually the document id so here we'll say document id but the label that will render within the table is going to be the order id right and then finally we want to display order total but the label for this will set to be just amount right so those are our columns and what we want to do is we want to map that within our table head and the table row here so here we'll here we're just going to call columns.map right we're going to first of all we're going to get the column and then the position that we're currently mapping within the array and then we'll have an explicit return where we call a table cell sorry not table container table cell component and what we want to render here is actually well it's from column so here what we'll do is we're going to get the column so we'll say console destructure from column right and what we want to get is the the label right and we're just going to render that here but we need to pass some props here so the first one is going to be the key because we are mapping and this is react so we'll use the position there and then we also want to pass the styles now we haven't defined styles but this is an object that we're going to pass to the various components [Music] that we're going to use for material ui so these are just some basic configuration you can review the documentation yourself and set this as you wish but i'm going to set the font size to 16 pixels i'm going to set the cursor to be pointer and i'm going to set the width which is probably the most important one i'm going to set that to 10 and then i'm just going to pass that into the table cell using the styles prop right so that's our head done here okay so i'm finally ready to build out my table body but before i can actually map my orders i need to verify that we actually have them so to do that i'm going to call array dot is array and pass it the orders once we have done that we we can be sure we'll be able to safely call orders.length because we know it's an array and we can check that it is greater than zero which means that we have orders once we've done that what i can do is i can go ahead and map orders so i'll say orders.map and what i'm going to get here is the row right as i map the orders i'm going to map my rows and i'm going to get the position that we're currently mapping right and then i'm going to have an explicit return here and what we're going to return is actually going to be a table a table row and what we'll need to do here is pass it the key which again is the position now keep in mind that i'm now mapping the row right now what i actually want to do is very similar to what we did in our table head i need to map the columns array to get the data the value from my row right so if that doesn't make sense right now then just bear with me but what i'm actually going to do is copy the code that we put in the head of our table because we have to do something very similar here so i'm just going to copy that in here but i am going to have to modify it slightly so rather than the structure label from column i'm going to store this in a variable i'm going to call this column name right and this is just going to equal the column dot id and then we need the value so to get that we're going to say column right value is going to equal the row which we're currently mapping from our data but we only want a specific field from our data which is going to be the field we're currently mapping on the columns array so i have that in column name i'll pass that here and that's going to give me the value from the data that we're currently mapping so in other words what we're doing is we have columns when we map our our order created date which is the first field we want to render within the table we are basically going to call that here right that's how we get it however we can't just go ahead and render the value within the table cell because that would actually throw an error the reason is we have a bunch of different data types stored within our collection right so we have a timestamp for example which we can't just render here because it would be invalid so we actually need a way of formatting the text so up here what i'm going to do is i'm going to create a function so i'll just say const format text right what it's going to do is it's going to take two things it's going to take the column name and the column value right and it's going to be a switch function right it's going to take the column name and it's going to have a default case which will just return the column value here but we are going to have um two cases where we want to change the value right for very specific uh fields so the first case is our order total right so we'll do that by saying that for the case that we are mapping our order total which is here we're going to return a string but what we want to do is we want to prefix this with the pound symbol so we're going to prefix it like this and we'll just pass in the column value right and this is just going to allow us to pre-append the uh the pound symbol here i'm also going to have another case which is where we are mapping our um our order created date now the reason that this is important is because this is going to be the type of um this is going to be a timestamp right so when we return this we actually need to return something we're going to need to use a library here so what i'm going to import here is moment we're going to import that at the top of the file from a moment we installed that just a little bit earlier and what that will allow me to do here when i return it is i'm going to call moment i'm going to pass it the column value and the format that i want to return this in right is going to be whatever format that you like here i'm going to specify dd uh the the day the month and the uh the year that's the format i want to return that okay so now i have my format function and by the way if it isn't the order total or the order created date we're just returning the value because that is fine right so in this case uh the document id it isn't going to get caught here so it's just going to return that and that's fine because it's just a string so hopefully that makes sense if it doesn't then please just bear with me but here we're going to create another const here and we're going to call this the formatted the formatted text it's going to equal format the format text function that we created here right and all we're going to do is just pass in the column name and the column value and then we're going to render the formatted text here okay so once we've done that let's come over to our page component for our dashboard and the first thing we need to do is import our order history component so we'll import order history component from the components folder so we're going to components slash order history and we're just going to render this component so instead of returning a h1 here let's return a div with we'll have h1 inside of that we'll just call this order order history right and underneath that will we we will render our component we need to posit our orders which we don't have access to yet so what we're going to do is we're going to import our um our orders data we're going to destructure that from the state from a redux store we're going to get our order history right and we'll get that from orders data dot order history.data and then we can destructure that here so we'll get our order history and we can just pass that into the component using the order it's actually orders prop so let's save that okay so as you can see we're successfully rendering our users order history within the browser using our table from material ui but i can spot two small bugs right so the first bug is that our styles are not being inherited because the text is too small and the other problem is that um we have an invalid date right so we need to fix those two bugs so we're just going to come back over to the text editor and our order history component uh to fix the date we just have to when we pass in our column value here right to moment uh we have to just tag on nano right because this is actually an object we just need to pass in the nanoseconds and then uh further down for styles the prop is not styles it's just style right so i made a mistake with the prop name if i change that on both the table cell components in the body and the head i can come back over to the browser and if i come back over to my account you'll see that our table is now displaying correctly at this at this point we are successfully rendering our order history but we're only displaying our order date order id and amount there is currently no way of showing the user the order details which is what we now need to work on next what should happen is the user should be able to click on one of these orders and take the user to another page where they can view their own that order's details view the items that were purchased the amount and the individual prices of each item so to do that we need to come back over to our text editor and what we need to do is i'm just going to go ahead and close these two files here and come back over to our redux files we need to write out some more code here and the first thing is our order our orders types we need two new types the first is going to be get order details start so we'll say get get orders order details start again the value is going to be the same as the name of the key and then secondly it's going to be set order details and again the value is going to be the same as the name of the key now that we've created our types we need to create the corresponding actions for those types so what we'll do we'll come over to our actions file so orders dot actions we'll say export const get order details start it's going to take an order id and then it's going to be a simple action with a type and payload so we'll say the type is going to be orders types dot get order details start and the payload is just going to be the order id and then we'll also need a another action to set the details in our redux store so we'll say x export const set order details it's going to take an order here and again it's just going to return a simple type and payload so the type will be orders types dot set order details and and the payload will just be the order itself okay so now that we've written out our actions we need to write our sagas so i'm going to come over to my sagas files this is order.sagas and i'm going to create a new generator function here so here we'll say export function again it's a generator function so we need that asterisks after the function keyword and then we're going to call this on get order details start right we're going to yield take latest we're going to call pass in the type we're listening for so order types dot get order details start and then the name of the generator function we're going to handle this async code within so we'll say export function it's a generator function we'll just call this get order details it's going to receive the full complete action including the payload which we're going to destructure and within this we're going to have a try a try catch which is going to get an error which we can log for now i'm going to comment that out right and we can come back to that but we will need to pass this in to take latest and we will need to export this at the bottom of the file so i'll call here this i'll here i'll say call and pass it the name of the generator function that we've defined take latest okay so at this point we're ready to write out our helper function that we can use to get an order from our firestore so to do that i'm going to open up my orders helpers because we need to write another helper function so all we need to do here is just define our helper function so here i'm just going to say exports const handle get order equals a function so it's just going to get the order id right this is going to return a new promise right so we're going to get resolve and reject right and then all we need to do is call firestore we're going to look at the collection our orders collection we're going to look for a specific document which we're going to get by the uh the order id that was passed in here right and then all we have to do is call the get method and then what we can do because that returns promise we can just say then we'll get snapshot right and then what we can say is if the snap dot exists is true then we can call resolve because that means that it exists and we've got the order right but we can call use a spread over spread operator here we can pass in the snap dot data that's going to return the data that's on that snapshot on that document but to get to pass back the document id we'll say document id is going to be the order id that was originally passed into the helper function and then all we have to do here again is just catch any errors so here we'll just say catch we'll get the error if there was one and we can call reject and throw the error okay so now that we've written our helper function let's come back over to our saga and what we're going to do is we're going to get the order we're going to store that in a variable so we'll just say const order right so const order equals yield and we'll await the response so where we import our helper functions here so order helpers we are going to now import handle get order and we're going to call that here right but we're going to pass in the payload which of course is going to be our order id right now once we've got that once we have the order we need a way of setting it so you'll remember we also created set order details so we need to dispatch that so where we import our order actions here we also need to get our set order details and again here we're just going to call yields put and we're going to dispatch set all the details with the order right so although this action is going to get dispatched it's going to pass the order we haven't set up our reducer to update our store so i need to come back into my order orders reducer and we're going to create some new initial state which is going to be order details right which is just going to be an empty object by default and then we need to create a new case so this is going to be the new case we'll specify order types dot set order details right we're going to return the state but we're going to set the order details to be the action dot payload right you can just add a semicolon here okay all we need to do now is create our order details page so i'm just going to go ahead and close these files so it's a little bit easier to navigate i'm going to come back into my pages component and i'm going to create a new file here we're going to call this our order slash right so this is my new orders page component for now let's just import react from from react it's going to be a functional component we're just going to call this order right um we don't need to worry about props for now at least we're going to have an explicit return for now we'll just return a div with a h1 we're gonna just pass in the order id which we're going to come back to and then what we can do here is we can just export this component so we'll just say export default order and we'll come back to this but what we want to do is just create the route so let's go over to our app.js this is where obviously we configure our routes and we need to import our new page component so we'll import order from pages slash order okay now we can just define our route so i'm just going to come down and just above the admin route here we're going to create our route so i'll create a new route here right we're going to specify the path right which is going to be slash order and then we need a url param which we're going to call order id we'll then call the render prop here and we will return our component which we are going to wrap with auth because the user needs to be signed in to access this route we want to use the the dashboard the dashboard layout and the component we obviously want to render is our order component so let's save those changes okay so the next thing that we need to do is we need to actually dispatch the action to go out and fetch our um our order right so to do that what we're going to do is we're going to import something from react router dom right which is the use params hook okay so what we can do is we can just call that hook here so we'll just call that use params here and that will give us access to our order id right so this is the url param we defined when we created our route we're going to use that within the use effect hook so we'll call use effect here and we're going to use the use effect hook to dispatch the action we need to fetch the order details we're not going to pass in anything to our dependency array because we only want this to run when this component is initially mounted but we are going to need some more things here so we're going to need for example the action we want to dispatch so to get access to that we need to go into the redux folder orders and our orders action we need to import the get order details start and we also need something from react redux so we need to import that so from react from react redux we need to import use dispatch and use selector so first of all we need to get access to dispatch so here we'll say dispatch equals and call the use dispatch hook we'll then pass that here to our use effect hook and we will we will dispatch our action here with our order id right so this will actually dispatch the action and it will fetch and this will fetch the data from our firebase database now to actually get access to the order details from our redux store we need to map our create our map state function here so what we're going to do is we're going to get the um first of all we're going to get the order data right and then we want the order details which we can get from order data dot order details and then all we need to do um is use the use selector hook so we'll say here cons we'll destructure from calling our use selector hook and passing in our map state function and we can destructure here our order details now i can immediately destructure from our order details right so i can destructure here the order total and the reason i want to do that is because at the bottom of the file i want to have a h3 where i pass in the total which is the order total here and what i'm also going to do is where i have my order id here i'm going to render again from my url param the order id here right so at this point i'm able to see that so at this point all i'm doing is i'm fetching the order details and i'm displaying the order id and the total right so let's see how this will work what we need to do is come back over to our dashboard right and we need to link these two pages up so at the moment this is my order history component and within this component i have my individual fields right where i have my i render my initial orders so on this file we need to import something from react router though right which is use history and to actually get access to that what we'll do at the top of the file here let's say const history equals use history and call that hook and then what we can do is where we map our orders right what i can do is i can get the document id from the row so from the row here i can destructure the document id and the reason we want to do that is here on our table cell sorry on our table row right if i just tap this in a little bit i can call the on click event right so when someone clicks on an order we want to call history dot push right and then we'll push them to orders slash the document id right which is then going to map to the route we defined for our order details where it expects the order and the order id and then when we get the order id from our url params in order we're going to dispatch the action here passing in our order id which then goes out and fetches it and passes it to our redux store which we then destructure here and we can use that within our page and components so let's kind of see this working in the browser okay so let's test this out in the browser as you can see this is our order history i can now click on this and as you can see this is taking me to orders slash the order id now this isn't looking like much because i've just realized i entered the wrong url so let's just come back over to the text editor instead of orders it should be order save that change right that's on our order history component let's come back over here and let's go back and let's click on our order again and as you can see we have an error right so um let's just check our um so let's just check our root reducer here and you can see this is actually orders data so if i come back to my my order component i was getting order data so it needs to be orders data let's save that change come back to the browser let's come back over and as you can see i'm now getting the order id and the total amount which is cool but what i want to do now is i want to render the order details right so i want to render the the cart i the actual items that were purchased the the amounts and maybe the thumbnail image and the quantity that was purchased so let's work on that okay so now what we need to do is we need to create our order component right so this is going to render out our order details um using the the same material ui table that we used for our order history component so again within my components folder i'm going to create new file we're going to call this we're going to call this our order details slash index.js right now again this is going to be a simple functional component so let's say import react from react we're going to create a functional component we're going to call it order details right this time it's just going to take in an order right and then we're going to have an explicit return which we're going to come back to in a second and at the bottom of the file we just need to remember to export this by default and at the top of the file we need to import from material material ui core so we need to import our table container our table our table head our table body a table row and our table cell okay so then within order details will we render this out we need to render it so let's render our table container our table we need a table head right we need within that we're going to have it table row and below our table head we need a table body which we're going to come back to right now just like we did before we need to create our columns array so above order details we're going to create a const called columns which is going to equal an array of objects with an id label with an id and label so here we're going to have id the first one is going to be our product thumbnail so we'll say product thumbnail is just going to be an empty string because we don't want to um to actually have any a title for that for that for that column then we want the product name here and again the label for this is going to be name then we're going to have another id here this is another column so it's going to be product price and again the label here is just going to be price we have another column finally which is for quantity right and the label for this is just going to be quantity okay so for our table head all we need to do is map our columns and render out the labels so let's go ahead and do that we're just going to render columns right dot map we're going to get the um the the col and the position that we're currently mapping in the array we're going to have an explicit return where we render a table cell and we're going to render the label so we'll just say call dot label we need to specify a key here so we'll just pass it the position that we're currently mapping and again we need that styles array right sorry styles object so we'll say const styles equals it's an object so we'll set the font size here to 16 pixels and the width we're going to specify as 10 percent we're going to pass styles in here so it's the style prop right so we just need to pass that here and that is our head section done what we then need to do is we need to destructure from order so const we'll just say here cons order items equals order order dot order items and then again let's come down to our table body here and what we need to do first of all is verify that the the data is valid so we'll say array dot is array we'll pass it our order items we also want to check that our order items dot length is greater than zero if that is the case what we can do is we can go ahead and map our order items so we'll say order order items dot map we're going to get the current row and the position in the array that we're currently mapping and then we're simply going to return here a table row component so again we need to pass the key because this is react so we'll pass that position and then just like we did before we're going to map our columns again so let's actually copy this code let's copy that in fix our indentation but what i'm going to do here is again i'm going to get the the column name so that's going to equal the call id we also need the the value so we'll say column value equals and again we're going to map that against the data so we'll say row column name right so we're going to get the when we map through our columns right so for example when we map our product thumbnail here we're going to get the product thumbnail from the row that we're currently mapping from our order items but like i did i i like i mentioned before it's very important that you understand we cannot always always render the data types that we will map so we need to format it so again we need to come up to the top of the file here and create our format function so we'll say const format text equals function this is going to take two things it's going to take the column name and the column value and then what it's going to do is we're going to have a switch function which is going to take the column name right we're going to have a default case where we just return the column value that's passed in right that's our default case however if the column name equals the product price right then what we're going to do is again we're going to we're going to return the product price with the pound symbol prefixed prefix to it so again here we can just return the column value um and we also want a custom case for our product thumbnail right so here we have our product thumbnail so if we're currently mapping our product thumbnail that we want to return a image right where we pass the source which is going to be our column value because that's going to be our source url and let's set the width to a hard-coded value something like 250 pixels or something like that okay so what we can do is we can call format text here right uh let's come down here and what we can actually do is when we render this let's just call format text and pass in our column value here where we go to render it and then the final thing that we need to do is actually render this component so don't forget that this component expects the order prop so what we're going to do is we're going to come back over to our page component so in pages we have our order component here we need to import our order details component so we'll say order details we want to import that from our components folder and our order details and then we simply need to render that component between our h1 and our h3 we need to pass in our order which we have here this is our order details we'll pass that in okay so let's come over and test this again in the web browser i'm going to go over to my account click on an order okay and i'm not seeing the orders so let's just come over and check the code um so my format text function expects both the column name and value i think yeah so i forgot to pass in the column name here to the format text function right so let's pass that in let's come back over to the browser return to my orders page let's click on and order there you go so i'm now able to see the individual items that were purchased with the uh the quantity and the total amount and the order id okay now finally the last thing that we need to do to finish off our order history components is just come back over to the text editor and on my order details component at the top of the file i need to import something from react redux which is the use dispatch hook and i need to import a action from my orders actions so i can come in here go to redux slash order slash orders actions and i need to import set order details and then to get access to dispatch at the top here i'm going to import i'm going to set cons dispatch equals use dispatch and call that hook and i need to also import the use effect hook so use effect and we can call that hook here so we'll just say use effect right we only want it to run once so we'll pass in an empty dependency array but i'm actually not going to put the code here immediately i need to have a return here right and this will be called when the component unmounts which is exactly when i want to dispatch my action which is the set order details action and we're just going to pass in an empty object now the reason that we do this is that whenever you navigate away from this page what we're going to do is we're going to clear our order details state so that you don't persist that throughout your application which can create some uh ui user experience issues so this is just best practice just to clear that because if you return to this page you will need to fetch it again so that should be quite straightforward and that brings us to the end of this video tutorial as you can see the users are now able to view their order history and order details now before i sign off i just want to remind you guys that at the end of these tutorials i do create pull requests and i merge into the official github repository for this project i will be posting a direct link in the description of this video so please do go and check it out i also want to encourage you guys to check out my official youtube channel not only to find my other videos but also to find the official playlist for this series which again i'm going to be posting a direct link to in the description of this video but most importantly of all please do like comment and subscribe and don't forget to turn on those notifications thank you very much for following this tutorial and i'll catch you in the next one
Info
Channel: SimpleTut
Views: 3,664
Rating: undefined out of 5
Keywords: ecommerce, react, react redux, GraphQL, React Context API, Node, Node JS, redux, online store, stripe, stripe api, shopping card, paypal, firebase, react router, react router dom, routes, routing, Google Sign-In, Google Auth, Google Sign In Authentication, login, signin, react hooks, useEffect, useSelector, useDispatch, redux hooks, useState, material-ui, moment js
Id: Co4Pt5jA2ck
Channel Id: undefined
Length: 93min 41sec (5621 seconds)
Published: Sun Dec 13 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.