‫Welcome to the last lecture
‫of the Wild Oasis project.
‫So at this point, we have essentially
‫finished the application,
‫and so let's just fix a small thing or two,
‫and then wrap it all up.
‫Now, the main thing that I want to fix in this video
‫is a small bug that we left in our menus.
‫So right here, when I click, then that works just fine,
‫and the same when I click outside.
‫However, when I click here, and then click again,
‫the idea was that this should then close this menu again,
‫but that is not currently working,
‫and so let me show you how to fix this problem.
‫So let's open up our Menus file,
‫and so let's see,
‫yeah, this here is the function,
‫this handleClick where we actually do the opening
‫and the closing.
‫So here, let's add a console.log,
‫let's say, click,
‫and then let's also add a console.log here
‫to the useOutsideClick.
‫So let's, well, I will duplicate this and leave it here,
‫and here, let's now create a new function.
‫And so in this function, we will call the close function,
‫but we will also have a console.log saying,
‫close from click outside.
‫And you don't have to write this code,
‫this is just to show you why we have that bug right now.
‫So let's see what happens when we click here.
‫And so then indeed, we get click,
‫and then as I click again, watch what happens.
‫So we basically, whenever we click there,
‫we first close the menu,
‫and then here, in this next millisecond, it is opened again,
‫and so basically, what is happening here
‫is that when we click here while the menu is open,
‫it is closed for one millisecond,
‫and then it is opened immediately again,
‫and so we need to fix this part
‫where a click from the outside is detected.
‫So the way we do that is to pass in here the second argument
‫and set it back to false.
‫So remember how here, in this custom hook,
‫we are, by default, listening for events
‫on the capturing phase,
‫so we have listenCapturing set to true,
‫and so that is causing the problem in this situation.
‫So instead of listening in the capturing phase,
‫which is where the event goes from the DOM
‫onto the target element,
‫we now need to listen in the bubbling phase
‫where the event goes from the target element
‫back up to the document,
‫and this is actually the default way
‫in which the addEventListener works.
‫And so by setting this prop here, or this argument to false,
‫we will basically go back to that default way.
‫So let's try this, let's reload,
‫and so then we will see that this still
‫doesn't fix the problem, so let's click here,
‫and so now, we basically have the opposite problem.
‫So we click, which will then open,
‫but then immediately, we detect a click from the outside,
‫which will then close the menu again.
‫So let's fix that as well,
‫and so what we have to do is to come here to this function,
‫and then stop the propagation of the event,
‫so e.stopPropagation,
‫and so with this, the event will then never
‫travel up further in the DOM,
‫and can then therefore not be detected as a click outside,
‫so this part here should then no longer happen.
‫So let's see,
‫and nice.
‫So now, it works exactly as expected,
‫and then if we click outside here,
‫then is where we finally get this message,
‫and where the menus close in a situation
‫where we want it to close.
‫Great, so let's just get rid of this one, turn this back on,
‫and then very important, we need to pass in false.
‫So this was really just an issue with the DOM
‫and with how events work, so nothing about React,
‫but still, it is important that you keep knowing
‫about these things,
‫even if you build React applications
‫and not just vanilla JavaScript applications,
‫but anyway, now, this bug is fixed,
‫and the final thing that I want to do now
‫is to just get rid of this uploader,
‫and of course, take one final look
‫at this beautiful dashboard that we just built,
‫and notice how the loading spinner that we created here
‫really showed up only inside this component
‫and not on the entire page,
‫so that was one of the things that we did here.
‫And let's actually upload the bookings one more time
‫just so that later, when we deploy this project,
‫we then still get all this nice updated data.
‫All right, and then let's finally get rid of that,
‫so that should be in our sidebar,
‫and there it is.
‫Here, as well,
‫and nice, so that's gone as well,
‫and we could also remove here the React Query devtools,
‫but I think that they will automatically disappear
‫once we actually are in production,
‫so no need to take that away here,
‫and actually, there are two more things
‫that I want to fix right now,
‫and the first thing is if we open up
‫a booking detail page that doesn't exist.
‫So let's come here to see these details,
‫but let's say that for example,
‫we land on a page which has some ID that doesn't exist,
‫so that will create then a bug,
‫which will be caught in our error boundary,
‫so the boundary that we implemented in the previous lecture,
‫but this is still not ideal,
‫because we get this weird error message,
‫and really, what should be happening is not an error,
‫but just the information that this booking
‫couldn't be found,
‫and so let's quickly come here
‫to our Features, and then Bookings,
‫and this is in the booking detail,
‫and so here, we can say, if no booking, I believe,
‫but let's actually take a look
‫at what the booking is right now.
‫Well, we cannot, because the React Query devtools
‫is no longer there.
‫So I just want to see what the booking is in this case,
‫if it's undefined or...
‫So let's check that, and yeah, it is undefined.
‫So as I was saying,
‫then here, we can do, if there is no booking,
‫then we return again that empty component
‫that I believe we have used before,
‫and there, we can specify the resourceName prop,
‫and here, it's called Booking,
‫and so let's see, let's reload here,
‫and that's a lot better.
‫So now, we simply get the information
‫that no booking could be found.
‫All right, and now to finish, at least for now, at least,
‫let's come here to our, well, actually to our context,
‫to our dark mode context,
‫because remember how initially we set the dark mode here
‫to false by default, but instead of doing that,
‫we can actually use as a default value the setting
‫that the user set in their operating system.
‫So for example, I have dark mode by default
‫on here in my operating system,
‫and so we can get access to that,
‫basically using a media query,
‫which we can run with window.matchMedia,
‫and then here, we kind of pass in a media query.
‫So here we need the parenthesis,
‫and then prefers-color-scheme: dark,
‫then close that,
‫and then we can check if this media query matches.
‫So indeed, in my case, it does match,
‫and so for me, if we now used this here
‫as the default value,
‫then on the first time that I opened up the application,
‫it would already be in dark mode.
‫So let's use that here instead of this false,
‫which is not going to change anything,
‫because at this point, we already have that value
‫in our local storage,
‫but actually, let's check what happens if we remove that.
‫So somewhere here, we should...
‫Yeah, here it is.
‫So here, we can remove this, and so if I now reload,
‫then it should be automatically in dark mode,
‫and indeed, it is, nice.
‫So just another small feature here,
‫but I think this is another really nice one.
‫Now, in the future, if more bugs arise here,
‫so if any of you finds any bug in this application,
‫then please report it in the Q&A section,
‫and then at some point, I will fix it in this application,
‫and so I might then do that exactly in this video as well,
‫but for now, with all this being said and done,
‫we actually finished this project.
‫So congratulations for building the probably
‫biggest project ever in your web developer journey.
‫So this was a really long and a really big one,
‫but I hope that it was totally worth it,
‫and I really hope that you enjoyed it as much as I did,
‫and that you walk away with tons of valuable skills,
‫not only React skills, but also skills
‫on front end development in general.
‫Now, there are a few more things
‫that we could have implemented in this project,
‫but I had to cut it off at some point,
‫otherwise, we could have gone for 10 more hours,
‫but if you feel like developing this even further,
‫I have a few suggestions for you,
‫and the most important one would definitely be
‫to actually create new bookings right here
‫from this application.
‫So basically, right now, if a new guest
‫appears in the hotel,
‫we have no way of creating a booking
‫and checking them in, right?
‫So right now, all the bookings that we have
‫were just part of the sample data,
‫but we don't have any way of creating them,
‫and so this would be a really nice challenge for you,
‫and I actually built this myself,
‫but it is a real challenge,
‫and it's gonna take a lot of time,
‫and so that's why I decided to not include it here
‫at this point.
‫You could also add the feature where a booking
‫can be edited,
‫and you could even add check in and check out times.
‫Now, another thing is that in the real world hotel,
‫the cabins or the rooms actually don't have a fixed price
‫throughout the entire year,
‫so instead, prices vary basically every single day,
‫and so you could somehow implement that
‫in this application as well,
‫so where here, the users could set a different price
‫for every single different day.
‫Next up, another idea that I had
‫is that you could add a restaurant to this hotel.
‫So you could add another item here in the sidebar,
‫which would take the user to a page
‫where they can register a bill value
‫each time that the guest goes to the restaurant,
‫and so then at checkout, that bill would have to be paid.
‫And finally, also during checkout,
‫we could actually lead the user here to a page,
‫so when we click here on Checkout,
‫then that could lead to a page where we could then
‫generate a PDF invoice that we could then mail to the user,
‫since we already have their email address as well.
‫Okay, so these are just a few ideas,
‫and I'm sure you can come up with even more if you want,
‫and if you do implement any of these,
‫then please make sure to share it with me in the Q&A,
‫or maybe even in the GitHub repo.
‫All right, and so now, it's time to finally
‫close up this section,
‫but we do actually have one more thing to do,
‫which is to deploy this project to production
‫to a live server so that you can actually
‫share it with everyone,
‫and so let's go do that in the next super short section.