‫In this video,
‫we're gonna implement the my bookings page.
‫So, basically we're gonna render a nice page
‫containing all the tours that a user has booked.
‫And let's start by adding a new route to our viewRoutes.
‫Okay, so we have me and so let's after that
‫then create the my-tours.
‫So I'm duplicating this one, my-tours,
‫then also this route needs to be protected
‫so that only currently logged-in users
‫can access this page, of course.
‫And then, in our viewsController,
‫we're gonna have a controller called getMyTours.
‫MyTours like this, okay?
‫And that's actually it for now,
‫so let's go ahead and create this controller now.
‫Okay, so we have all these gets here,
‫get tour, get log-in form, get account.
‫So let's put this one here as well.
‫And so now, what we need to do here
‫is to find all the tours that the user has booked.
‫So, basically, first we need to find all the bookings
‫for the currently logged-in users
‫which will then give us a bunch of tour IDs,
‫and then we have to find the tours with those IDs.
‫So, basically, find all bookings and then
‫find tours with the returned IDs.
‫So basically the IDs of the bookings for the user, right?
‫Now, instead, we could also
‫do a virtual populate on the tours,
‫and it would be great if you would implement
‫this on your own exactly as we have done it before
‫with the tours and the reviews,
‫but here in this function I actually wanted to show you
‫how we can do it manually
‫because I think that's also kind of important
‫and actually a virtual populate
‫should work something similar to what we're gonna do here.
‫And so you see that actually we need two queries
‫in order to really find the tours
‫corresponding to the user's bookings.
‫Any way, let's now start,
‫so let's create a variable for all the bookings, await
‫and now I think we don't have the bookings here yet, nope.
‫So Bookings here, and bookingModel.
‫And here, of course, it's just booking, all right.
‫So await Booking.find, and now remember
‫that each booking document has a user ID, right?
‫So here in the Schema remember
‫we have the tour ID, the user ID,
‫and then all this other data,
‫and so what we're gonna do now
‫is to basically query by the user ID, okay?
‫And so that will then return us
‫all the tours that belong to the current user, okay?
‫So, not this one.
‫So tour should be equal to req.user.id.
‫Then here async, and as always, catchAsync as well.
‫So these bookings now contain all
‫the booking documents for the current user,
‫but really that only gives us the tour IDs.
‫And so now we want to find the tours with the returned IDs.
‫And so the next step is to basically
‫create an array of all the IDs,
‫and then after that query for tours
‫that have one of these IDs, all right?
‫And this will make a bit more sense
‫once we actually implement what I just explained.
‫So tourIDs is equal to bookings
‫and now we're gonna use a map
‫to create a new array based on a callback function
‫which is this one,
‫so the current el.tour.id.
‫So, what is this going to do?
‫Well, basically this loops through the entire bookings array
‫and on each element it will grab the el.tour.
‫And actually, we don't even need the ID here
‫because the tour itself is already the tour ID, right?
‫Then in the end, we have a nice array
‫with all the tour IDs in there here
‫and that's because we used a map.
‫Okay, then having all the tour IDs,
‫we can actually get the tours corresponding to those IDs.
‫So await Tour.find and we actually want to find by ID,
‫but we cannot use the .findbyid
‫because here we actually will need a new operator.
‫And said operator,
‫which I'm not sure if we have used before,
‫is called in.
‫So, in tourIDs.
‫So basically what this is going to do
‫instead it will select all the tours
‫which have an ID which is in the tourIDs array, okay?
‫So that's quite straightforward,
‫but it's very great to know
‫that we can use this very handy in operator here, okay?
‫And so that's actually one of the reasons
‫why I wanted to do this manually
‫instead of just doing a virtual populate like we did before.
‫But again, it would be nice if you would go ahead
‫and actually implement that also
‫just for the fun of it, you know.
‫Okay, and with this we actually
‫have our tours ready to be rendered.
‫So, res.status as always,
‫and then render them, all right?
‫And actually, we don't even need a new template for this.
‫We're simply gonna be reusing the overview, okay?
‫So we're gonna end up with a page
‫that looks very similar to the overview,
‫but only with the tours that the user has booked.
‫So, up here and to get overview,
‫we then actually passed in all the tours, okay?
‫So basically all of them.
‫And so now, we're gonna have something very similar
‫but of course only passing in the booked tours.
‫So, where's that?
‫All right, so the title's gonna be My Tours,
‫and again passing in the tours variable.
‫Okay and that should be it.
‫Now of course we could also have created
‫a whole new card for these bookstores
‫with some more relevant information
‫about each of the bookings,
‫but in this case that's not really important.
‫Now, right?
‫So, we're actually ready to test this
‫because we already implemented the route here before.
‫And so that's my-tours.
‫Oh, but actually let's set this link here
‫right on the user account page.
‫So this my-tours should of course have
‫it's own link right here in the account.
‫So in that left column,
‫so that's right here in My bookings,
‫so we have this first one here
‫which is for the link, remember.
‫And so right now, basically all of them point no where,
‫but now for the bookings we actually have a link.
‫And so that is my-tours.
‫And we could have called it bookings as well,
‫but that's not really important anyway.
‫So, now we're ready to test this.
‫Let's actually log out of this user,
‫and then log in as our other user, Laura.
‫All right, and so let's see what we get here
‫and that's taking way too long,
‫so let's take a look at our code, edit our terminal here.
‫Okay, so there's no error here,
‫but also it looks like nothing is really happening here.
‫So the my-tours route here doesn't even show up, all right.
‫Now in order to find this bug,
‫I actually had to do some debugging outside of this video
‫because it was really a hard one to find, okay.
‫First, there's a small error here.
‫So this here should actually be user and not be tour.
‫So I explained it correctly back then,
‫where I said that we need to filter by the user,
‫so tours where the user is equal
‫to the user coming from the request,
‫but then for some reason I did it wrong here, okay?
‫But that's not the main bug actually.
‫So not the one preventing the page from actually loading.
‫The error that causes that to happen
‫is right here actually in the booking model.
‫And it's down here in this pre find middleware.
‫And the problem is that we do never
‫call the next middleware here, now right?
‫So again, this is a pre-middleware.
‫And all of the pre-middlewares have access
‫to the next function and so,
‫at the end of these middlewares,
‫we always have to call next.
‫Otherwise, our process really gets stuck, all right?
‫So give that a save, can actually close this one.
‫And so now let's try that again
‫and now indeed we have my tours,
‫but it is empty since this user never really did a booking.
‫So, let's try that out now,
‫and let's book the forest hiker.
‫So that should still be working,
‫and indeed it does, very nice.
‫We have the email address pre-formatted
‫and now, as always 4242.
‫So we did the booking before actually with this user,
‫but before we implemented the booking model
‫and so therefore we never really
‫created a booking in our system.
‫All right, so payment accepted
‫and now let's see and here we go, great!
‫So that logic that we just implemented actually worked
‫and so really the only problem was
‫that next missing in the middleware.
‫And just like that, we completed yet another page
‫of our dynamic website.
‫And so next up, all there's really left to do at this point
‫is to finish the bookings API.