Coding

#18 Bookings | Build a Complete App with GraphQL, Node.js, MongoDB and React.js

  • 00:00:01 hi and welcome back so we're able to
  • 00:00:04 create events here with our modal to
  • 00:00:06 view the events and for events we didn't
  • 00:00:09 create we can even book them or at least
  • 00:00:11 we'll be able to do that at the end of
  • 00:00:13 this video because right now we only see
  • 00:00:15 that modal but at the end of this video
  • 00:00:16 we'll be able to make a booking and see
  • 00:00:19 our bookings so that only the feature to
  • 00:00:22 cancel booking is missing thereafter so
  • 00:00:24 let's dive in and let's make sure we can
  • 00:00:26 book ourselves some events
  • 00:00:31 so let's make sure we can finally all to
  • 00:00:33 book an event we get this book button
  • 00:00:35 here after all so of course it should do
  • 00:00:38 something now back in a code if we have
  • 00:00:40 a look at our schema here we see that
  • 00:00:43 for booking we have the book event
  • 00:00:45 endpoint we can't re it which requires
  • 00:00:48 just an event ID so for that in the
  • 00:00:52 events page there we get that modal with
  • 00:00:54 the book button and we got the book
  • 00:00:57 event handler in there as well here it
  • 00:01:00 is now I want to send a request to the
  • 00:01:03 back end when this handler here this
  • 00:01:06 method runs so we can't actually of
  • 00:01:09 course go to fetch events there and use
  • 00:01:14 that logic we can copy that whole
  • 00:01:17 request logic here and move that into
  • 00:01:20 the book event handler and now in the
  • 00:01:23 book event handler obviously all nots in
  • 00:01:25 a curie but a mutation because if you
  • 00:01:28 have a look at the schema again it's a
  • 00:01:31 mutation book event is a mutation the
  • 00:01:33 name is the book event and the argument
  • 00:01:35 name is event ID so back here um book
  • 00:01:40 event is the name and I need to pass an
  • 00:01:42 argument which is event ID and that
  • 00:01:45 argument is my ID of course and I will
  • 00:01:49 inject this here between my quotes now
  • 00:01:53 for that here I will access this state
  • 00:01:55 selected event underscore ID that is
  • 00:01:58 just the idea one a forward and then I
  • 00:02:01 will call book event now let's have a
  • 00:02:04 look at the schema again we see we get
  • 00:02:06 back a booking object and that booking
  • 00:02:09 object here has an ID has information
  • 00:02:12 about the event we booked about the user
  • 00:02:14 who booked it and it has these two
  • 00:02:17 timestamps here now let's not fetch the
  • 00:02:20 event and user information but I want to
  • 00:02:22 have two to date and I want to have to
  • 00:02:25 create it at and update it at time steps
  • 00:02:28 here let's say so this is my book event
  • 00:02:30 handler query now then we execute this
  • 00:02:33 query we will have to authorize ourself
  • 00:02:37 ourselves so we'll add the authorization
  • 00:02:40 header here again just as we did it for
  • 00:02:42 creating an event so we
  • 00:02:44 can copied add logic here the token is
  • 00:02:46 fetched from the context so here let's
  • 00:02:51 set this to a value of bearer token or
  • 00:02:56 to be precise here this context token
  • 00:02:59 then here we make our default checks and
  • 00:03:03 for now I will just console.log response
  • 00:03:07 data is low loading something I don't
  • 00:03:11 need to manage here because I never set
  • 00:03:13 it to true here so we should be able to
  • 00:03:15 actually now execute this request
  • 00:03:18 already and make a booking now the user
  • 00:03:22 for whom the booking is made is
  • 00:03:23 determined on the server based on the
  • 00:03:26 token we passed to the server because if
  • 00:03:28 you remember dealy the videos were we
  • 00:03:32 created the api on the server we do
  • 00:03:34 actually extract the user ID for they
  • 00:03:36 given token now first problem is I can
  • 00:03:39 view the details here if I'm not logged
  • 00:03:41 in and I can click book here but
  • 00:03:43 actually if I'm not locked in I should
  • 00:03:45 not be able to book so that's a tiny
  • 00:03:50 change I will make first of all before
  • 00:03:52 we test this because it's really
  • 00:03:53 something I don't want to have here the
  • 00:03:56 confirm text here will actually be based
  • 00:03:59 on my off status so here I can check
  • 00:04:02 this context token and if I do have one
  • 00:04:05 then I'll set book as a text otherwise
  • 00:04:07 I'll just set it to confirm now in on
  • 00:04:11 confirm the book event handler is
  • 00:04:13 executed but in there I will basically
  • 00:04:16 not do anything if I'm not locked in so
  • 00:04:19 if not this context token if I don't
  • 00:04:23 have a token then I will return here the
  • 00:04:27 one thing I will do is though I will
  • 00:04:28 call set state and set selected event to
  • 00:04:32 null by the way that is also something I
  • 00:04:35 want to do when I'm done making my
  • 00:04:36 request to book an event because dad
  • 00:04:39 will close the modal so now with that
  • 00:04:43 let's reload here view details and click
  • 00:04:47 confirm nothing happens let's now log in
  • 00:04:50 and wait for this to reload now here I
  • 00:04:55 see book and if I click book
  • 00:04:57 this does look too bad let's have a look
  • 00:05:00 at our console log here I got booked
  • 00:05:02 event pack and there I have all that
  • 00:05:05 data perfect so this works were able to
  • 00:05:09 book an event we can make a booking now
  • 00:05:12 of course one in the same user can make
  • 00:05:14 multiple bookings here as you can tell I
  • 00:05:17 made a number booking but that's
  • 00:05:18 actually something I'm fine here um you
  • 00:05:20 could have an event which you can book
  • 00:05:22 multiple times because maybe you're
  • 00:05:24 signing up family members obviously you
  • 00:05:27 can refine this in many many ways I want
  • 00:05:29 to show you the debayer picture how all
  • 00:05:31 these things work together and how we do
  • 00:05:33 connect our react front-end 2d graphical
  • 00:05:36 back-end and therefore I'm happy with
  • 00:05:38 this now on the bookings page it now
  • 00:05:40 would make sense to view the bookings to
  • 00:05:43 at least have a very basic first
  • 00:05:45 representation of the bookings made and
  • 00:05:48 therefore on this bookings page right
  • 00:05:52 when we load it actually so in component
  • 00:05:54 it mount I want to load all available
  • 00:05:56 bookings I will also need a state here
  • 00:05:59 and in my state I want to have is
  • 00:06:02 loading so that I can show a loading
  • 00:06:04 indicator and the bookings which is
  • 00:06:07 initially and an empty array so just as
  • 00:06:11 in the event page where I also have my
  • 00:06:13 events which initially is an empty array
  • 00:06:16 here in the bookings page I have my
  • 00:06:18 bookings now I will add a new method
  • 00:06:21 fetch bookings and that will just do
  • 00:06:28 that it will fetch my bookings so I can
  • 00:06:31 go to the events page again and then
  • 00:06:34 here copy that logic we used for
  • 00:06:38 fetching the events let's say where we
  • 00:06:40 construct the request body and then make
  • 00:06:42 the request and do the same in here and
  • 00:06:44 yes of course you can outsource all
  • 00:06:46 these API calls into a separate file to
  • 00:06:49 keep your event J's file a bit leaner
  • 00:06:51 that would be possible of course so now
  • 00:06:54 here in the bookings J's file we got the
  • 00:06:56 request body we make a query let's have
  • 00:06:59 a look at our schema again there we see
  • 00:07:01 we can make a query to Eve to do
  • 00:07:04 bookings excuse me and we get back a
  • 00:07:05 list an array of bookings we don't need
  • 00:07:08 to pass any arguments so I will make
  • 00:07:11 a request to bookings here and now for
  • 00:07:14 every booking which I get back I am
  • 00:07:16 interested in my ID in my let's say
  • 00:07:23 created at timestamp and then if we have
  • 00:07:27 a look at the schema again we see that a
  • 00:07:30 booking there has this event field right
  • 00:07:33 and I want to fetch some information
  • 00:07:36 about that event too so here I will
  • 00:07:38 access event and for the nested data
  • 00:07:40 there I will fetch the ID and the title
  • 00:07:44 and let's say the date because maybe
  • 00:07:47 that would be information that makes
  • 00:07:48 sense to be displayed on a booking then
  • 00:07:52 we make the request here and I said it's
  • 00:07:54 loading to false I right at the start
  • 00:07:56 here I want to set it to true so I will
  • 00:07:58 call this set state is loading and set
  • 00:08:01 it to true and then thereafter I set it
  • 00:08:04 to false and of course I don't update my
  • 00:08:06 events here but my bookings so all I get
  • 00:08:09 back here in all these fields is
  • 00:08:11 bookings and I should have a bookings
  • 00:08:12 field in the data field of my response
  • 00:08:14 because bookings is the name of the
  • 00:08:16 query so now I am getting my bookings
  • 00:08:19 here now to see whether that worked or
  • 00:08:22 not
  • 00:08:23 let me throw in a very simple unordered
  • 00:08:26 list where I access this state bookings
  • 00:08:30 and map each booking into a list item
  • 00:08:34 without any styling so really just to
  • 00:08:36 see if it works where I output booking
  • 00:08:39 event title and then maybe a hyphen and
  • 00:08:45 then booking created at yeah that is
  • 00:08:50 what I fetch here created ad maybe
  • 00:08:54 already wrapped in a date constructor so
  • 00:08:58 that we can call to local date string so
  • 00:09:02 this is what I want to output in my
  • 00:09:04 bookings file now let me login because I
  • 00:09:12 can only view bookings if I'm locked in
  • 00:09:14 and let's go to bookings here and I
  • 00:09:18 don't see anything
  • 00:09:19 let's check the network tab and there I
  • 00:09:23 don't have any
  • 00:09:25 Qwest which makes a lot of sense because
  • 00:09:27 I did add my fetch bookings method but
  • 00:09:30 of course I'm not calling it here in
  • 00:09:32 component did mount that this is
  • 00:09:33 something I should do so here I should
  • 00:09:35 call this fetch bookings and now let's
  • 00:09:38 save that and log back in and by the way
  • 00:09:44 there is an hour issue you'll face if
  • 00:09:46 you log in and you go to bookings before
  • 00:09:49 your events loaded you'll get an error
  • 00:09:52 when the event data is there that try to
  • 00:09:55 update a component which is mounted
  • 00:09:56 anymore
  • 00:09:57 we can take care about this later here I
  • 00:10:00 got an error an internal server error
  • 00:10:03 let's see what's wrong message
  • 00:10:07 unaffiliated and that makes sense
  • 00:10:10 because I'm not passing my token here
  • 00:10:12 with a bookings fetch request I should
  • 00:10:15 have my authorization header here where
  • 00:10:18 I send bearer and then token but this
  • 00:10:21 context token also wouldn't work in the
  • 00:10:24 bookings J's file because I haven't
  • 00:10:26 connected this file with the off context
  • 00:10:29 yet so therefore let's import the off
  • 00:10:33 context from context of context and
  • 00:10:39 connected with the static context type
  • 00:10:41 so static context type equals off
  • 00:10:45 context and now we connected this
  • 00:10:48 bookings component to D context we have
  • 00:10:50 and therefore we can access this context
  • 00:10:53 and that will refer to our off context
  • 00:10:55 and there we have two token which we can
  • 00:10:57 now attach so therefore let's give this
  • 00:11:01 number to try and see if it now works if
  • 00:11:03 I do log in here and I go to bookings
  • 00:11:07 let's ignore the error which is about to
  • 00:11:10 come up and after some time I see my
  • 00:11:13 bookings which is good now I also forgot
  • 00:11:15 to add my key and we get that our error
  • 00:11:17 so first of all let me quickly add that
  • 00:11:21 key here so that for every booking I add
  • 00:11:23 the ID as a key but more importantly in
  • 00:11:26 events if I navigate a way so if I
  • 00:11:28 unmount this component I don't want to
  • 00:11:31 continue with my HTTP request or I'm not
  • 00:11:35 interested in the response anymore at
  • 00:11:37 least
  • 00:11:38 want to add some codes that basically
  • 00:11:40 ignores any response given back to me
  • 00:11:43 for that I will add a new property not a
  • 00:11:46 state actually but a new property to the
  • 00:11:48 events page component which I'll name is
  • 00:11:52 active and by default that is true
  • 00:11:56 now when I unmount this component and
  • 00:12:00 for dad let's say right before render
  • 00:12:04 here I will add component will unmount
  • 00:12:10 so when I'm about to unmount I will call
  • 00:12:12 this is active and set it to false and
  • 00:12:16 now in fetch events here this method
  • 00:12:23 when I try to call set state here also
  • 00:12:26 in the error case I will first of all
  • 00:12:27 check if this is active and only if it
  • 00:12:31 is active I will go ahead and make that
  • 00:12:33 state update so check if this is active
  • 00:12:38 and only update the state if this
  • 00:12:41 component is active and this should make
  • 00:12:43 sure that we're not trying to call set
  • 00:12:45 state and therefore update the component
  • 00:12:46 if it isn't active anymore so now if I
  • 00:12:50 submit this and I go to bookings we
  • 00:12:52 shouldn't see any error and after a
  • 00:12:54 while and unfortunately my network is
  • 00:12:56 really slow right now after a while we
  • 00:12:58 should just see the bookings so that's
  • 00:13:00 great now in the meantime until we see
  • 00:13:02 them let's at least show that spinner
  • 00:13:04 which we already have so why don't we
  • 00:13:05 use it here in the bookings component I
  • 00:13:08 will add a react fragment here for now
  • 00:13:12 so that I can have multiple sibling
  • 00:13:14 top-level elements and then I will
  • 00:13:17 import my spinner so import spinner from
  • 00:13:22 components spinner spinner and let's use
  • 00:13:26 that spinner then as long as we are
  • 00:13:28 loading so down there we can check this
  • 00:13:31 state is loading and with if we are
  • 00:13:34 loading then it will display my spinner
  • 00:13:36 here otherwise if we're not loading
  • 00:13:40 anymore I will display that unordered
  • 00:13:43 list because that means we have the data
  • 00:13:45 to display or we should have it at least
  • 00:13:51 so let me login again go to bookings and
  • 00:13:55 now we see that spinner here too and
  • 00:13:57 again unfortunately my network here is
  • 00:13:59 really slow at the moment but then we'll
  • 00:14:02 see our bookings appear here there they
  • 00:14:04 are
  • 00:14:04 obviously styling is not perfect but we
  • 00:14:07 can see them at least so with that we
  • 00:14:09 are able to add events to view events to
  • 00:14:13 load our bookings and to make a booking
  • 00:14:16 first of all that's also not that
  • 00:14:18 unimportant I'd say a lot of cool stuff
  • 00:14:21 added missing of course is a nicer style
  • 00:14:24 for our bookings here and then a
  • 00:14:27 possibility for us to cancel them
  • 00:14:29 because that if we have a look at our
  • 00:14:31 schema is of course the remaining part
  • 00:14:34 we now have creative and covered create
  • 00:14:37 user covered book event covered events
  • 00:14:40 bookings and login is all used cancel
  • 00:14:42 booking is missing that is what we will
  • 00:14:43 continue on in the next videos