﻿1
00:00:01,010 --> 00:00:03,730
‫And now to finish this project,

2
00:00:03,730 --> 00:00:06,593
‫let's finish this Stripe integration with webhooks.

3
00:00:09,310 --> 00:00:12,040
‫Let's start to remember how our Stripe integration

4
00:00:12,040 --> 00:00:14,210
‫actually works right now.

5
00:00:14,210 --> 00:00:16,750
‫We have this checkout-session endpoint,

6
00:00:16,750 --> 00:00:19,540
‫which gets called from our front-end.

7
00:00:19,540 --> 00:00:22,293
‫This will then call the getCheckoutSession function,

8
00:00:23,440 --> 00:00:25,100
‫so basically this one here,

9
00:00:25,100 --> 00:00:28,180
‫which will create a checkout session on the server

10
00:00:28,180 --> 00:00:30,300
‫using all of this information here,

11
00:00:30,300 --> 00:00:32,750
‫and then send it back to the client.

12
00:00:32,750 --> 00:00:35,170
‫Then after the processing of the payment

13
00:00:35,170 --> 00:00:37,280
‫is successfully done by Stripe,

14
00:00:37,280 --> 00:00:40,990
‫then redirect the user to this success URL,

15
00:00:40,990 --> 00:00:42,483
‫so this one that we created.

16
00:00:44,210 --> 00:00:48,120
‫Remember that onto this URL, we added the tour ID,

17
00:00:48,120 --> 00:00:50,920
‫the user ID, and also the price.

18
00:00:50,920 --> 00:00:55,040
‫We did that so that once this URL here is then called,

19
00:00:55,040 --> 00:00:57,920
‫our application would create a new booking document

20
00:00:57,920 --> 00:00:59,680
‫in our database.

21
00:00:59,680 --> 00:01:01,047
‫How did that work?

22
00:01:01,047 --> 00:01:04,743
‫In the my-tours route, we have a middleware for that.

23
00:01:06,040 --> 00:01:09,940
‫Remember, here in the viewRoutes, in my-tours,

24
00:01:09,940 --> 00:01:12,467
‫we have this createBookingCheckout.

25
00:01:14,770 --> 00:01:18,628
‫This function here, which basically from the query

26
00:01:18,628 --> 00:01:21,440
‫takes the tour, user, and price,

27
00:01:21,440 --> 00:01:25,023
‫and creates a entry in the database using that data.

28
00:01:26,350 --> 00:01:29,160
‫Basically we put this data on the URL

29
00:01:29,160 --> 00:01:32,500
‫whenever Stripe successfully processes a payment.

30
00:01:32,500 --> 00:01:34,990
‫And then this middleware function that we have here

31
00:01:34,990 --> 00:01:38,570
‫picks up the data and creates a new booking in our system

32
00:01:38,570 --> 00:01:39,960
‫using that data.

33
00:01:39,960 --> 00:01:42,790
‫And then after that, we basically redirect here

34
00:01:42,790 --> 00:01:45,763
‫onto the original URL without the query string.

35
00:01:46,770 --> 00:01:50,150
‫Now the problem with this was that it's not really secure.

36
00:01:50,150 --> 00:01:52,963
‫So, everyone who knows this URL structure,

37
00:01:54,010 --> 00:01:57,670
‫so this one up here, which tour, user, and price

38
00:01:57,670 --> 00:02:00,700
‫in the query string, can basically create a booking

39
00:02:01,761 --> 00:02:03,850
‫in our system without actually paying.

40
00:02:03,850 --> 00:02:07,120
‫So, all that we'd have to do is to open up this URL

41
00:02:07,120 --> 00:02:08,500
‫with some data in there

42
00:02:08,500 --> 00:02:11,680
‫and then from there automatically create a booking

43
00:02:11,680 --> 00:02:14,193
‫without going through the Stripe process.

44
00:02:15,540 --> 00:02:18,630
‫Remember how back then I said that we would fix this

45
00:02:18,630 --> 00:02:20,853
‫using something called webhooks.

46
00:02:22,090 --> 00:02:23,120
‫So, we do that now.

47
00:02:23,120 --> 00:02:24,090
‫Because for that,

48
00:02:24,090 --> 00:02:27,140
‫we actually need our website to be deployed.

49
00:02:27,140 --> 00:02:29,350
‫Now at this point, that's actually the case.

50
00:02:29,350 --> 00:02:31,833
‫And so, now we can implement these webhooks.

51
00:02:33,240 --> 00:02:35,663
‫For that, let's go to our Stripe dashboard.

52
00:02:37,400 --> 00:02:39,750
‫And I actually already have that opened here.

53
00:02:39,750 --> 00:02:43,903
‫And then go here to developers, then choose webhooks,

54
00:02:45,070 --> 00:02:47,970
‫and here, add a new endpoint.

55
00:02:47,970 --> 00:02:52,149
‫Now what is this endpoint here and this webhook?

56
00:02:52,149 --> 00:02:55,380
‫Basically we're gonna specify a URL here

57
00:02:55,380 --> 00:02:59,500
‫to which Stripe will automatically send a POST request to

58
00:02:59,500 --> 00:03:02,800
‫whenever a checkout session has successfully completed,

59
00:03:02,800 --> 00:03:05,740
‫so basically whenever a payment was successful.

60
00:03:05,740 --> 00:03:09,920
‫With that POST request, Stripe will then send back

61
00:03:09,920 --> 00:03:13,230
‫the original session data that we created in the first step

62
00:03:13,230 --> 00:03:15,623
‫when we created that checkout session.

63
00:03:17,540 --> 00:03:20,130
‫That's the reason why we actually needed our website

64
00:03:20,130 --> 00:03:23,010
‫to be deployed here because now we need to specify

65
00:03:23,010 --> 00:03:24,923
‫that real-life URL here.

66
00:03:27,170 --> 00:03:28,573
‫Let's grab that from here,

67
00:03:31,290 --> 00:03:34,150
‫and then add our route here basically.

68
00:03:34,150 --> 00:03:36,930
‫I'm going to call this one webhook-checkout.

69
00:03:41,620 --> 00:03:45,350
‫It's not in the API, and it's not inside the bookings.

70
00:03:45,350 --> 00:03:47,593
‫You will see in a moment why that is.

71
00:03:49,130 --> 00:03:51,210
‫Again, when a payment was successful,

72
00:03:51,210 --> 00:03:53,280
‫Stripe will then automatically post

73
00:03:53,280 --> 00:03:55,503
‫the original session data to this URL.

74
00:03:58,060 --> 00:04:00,380
‫Now we also need to select the event.

75
00:04:00,380 --> 00:04:04,740
‫And you see there are tons of events that we could use here.

76
00:04:04,740 --> 00:04:09,667
‫The one that we're using is the checkout_session_completed.

77
00:04:11,767 --> 00:04:12,650
‫Add that.

78
00:04:12,650 --> 00:04:15,083
‫Now you need to put in your password here again.

79
00:04:17,100 --> 00:04:19,110
‫And then there we go.

80
00:04:19,110 --> 00:04:22,665
‫This webhook then also has a secret here.

81
00:04:22,665 --> 00:04:25,850
‫This one, we will then also need in a second

82
00:04:25,850 --> 00:04:29,063
‫when we actually create our route for this URL here.

83
00:04:29,980 --> 00:04:32,430
‫Actually that's exactly what we're gonna do next.

84
00:04:33,750 --> 00:04:35,600
‫Basically in our system of course,

85
00:04:35,600 --> 00:04:38,840
‫we now need a route for this here

86
00:04:39,960 --> 00:04:43,840
‫so that when Stripe then posts the data to our application,

87
00:04:43,840 --> 00:04:46,233
‫we can then actually do something with it.

88
00:04:48,120 --> 00:04:52,233
‫Let's go back here and open up our application.

89
00:04:54,740 --> 00:04:57,743
‫We will actually add this route right here.

90
00:04:59,610 --> 00:05:03,100
‫Again, I will explain you why in a second.

91
00:05:03,100 --> 00:05:04,350
‫So, app.post

92
00:05:06,320 --> 00:05:08,850
‫and standard route and then of course we need

93
00:05:08,850 --> 00:05:10,810
‫a handler function for that.

94
00:05:10,810 --> 00:05:14,720
‫Let's quickly create it here in our bookingController.

95
00:05:14,720 --> 00:05:19,013
‫Let me call that export.webhookCheckout.

96
00:05:31,360 --> 00:05:36,360
‫Now I will have to import this controller into app.js.

97
00:05:39,210 --> 00:05:42,110
‫Let's do that right here after the bookingRouter actually,

98
00:05:45,150 --> 00:05:47,133
‫so this one and this one,

99
00:05:49,440 --> 00:05:51,383
‫controller and here also controller.

100
00:05:54,580 --> 00:05:56,050
‫All right.

101
00:05:56,050 --> 00:06:01,050
‫Now down here, that's bookingController.webhookCheckout.

102
00:06:04,800 --> 00:06:08,820
‫Now why do we actually define this webhook-checkout

103
00:06:08,820 --> 00:06:12,410
‫right here in app.js instead of doing it for example

104
00:06:12,410 --> 00:06:14,440
‫in the bookingRouter.

105
00:06:14,440 --> 00:06:17,950
‫The reason for that is that in this handler function,

106
00:06:17,950 --> 00:06:20,677
‫when we receive the body from Stripe,

107
00:06:20,677 --> 00:06:22,850
‫the Stripe function that we're then gonna use

108
00:06:22,850 --> 00:06:26,780
‫to actually read the body needs this body in a raw form,

109
00:06:26,780 --> 00:06:29,633
‫so basically as a string and not as JSON.

110
00:06:31,370 --> 00:06:34,140
‫Again, in this route here, we need the body

111
00:06:34,140 --> 00:06:37,555
‫coming with the request to be not in JSON,

112
00:06:37,555 --> 00:06:40,600
‫otherwise this is not going to be working at all.

113
00:06:40,600 --> 00:06:43,700
‫Now the thing is, that as soon as a request

114
00:06:43,700 --> 00:06:46,710
‫hits this middleware here, the body will be parsed

115
00:06:46,710 --> 00:06:48,563
‫and converted to JSON.

116
00:06:49,700 --> 00:06:54,650
‫It will then be put on request.body as a simple JSON object.

117
00:06:54,650 --> 00:06:57,520
‫Again with that, this route handler here

118
00:06:57,520 --> 00:06:59,180
‫would then not work.

119
00:06:59,180 --> 00:07:02,520
‫That's the whole reason why we need to put this route here

120
00:07:02,520 --> 00:07:04,557
‫before we call the body-parser.

121
00:07:05,580 --> 00:07:08,260
‫Now we still need to actually parse the body

122
00:07:08,260 --> 00:07:10,120
‫but in a so-called raw format.

123
00:07:10,120 --> 00:07:13,690
‫By the time I was recording this video,

124
00:07:13,690 --> 00:07:17,220
‫we could not do it with Express out of the box.

125
00:07:17,220 --> 00:07:21,500
‫And so, in this video, we download the body-parser from npm

126
00:07:21,500 --> 00:07:24,220
‫and use it as I show it in the video.

127
00:07:24,220 --> 00:07:28,340
‫However, like five days after I recorded this video,

128
00:07:28,340 --> 00:07:32,770
‫Express added the raw parser to Express as well.

129
00:07:32,770 --> 00:07:37,000
‫Now we can use express.raw instead of having to install

130
00:07:37,000 --> 00:07:39,523
‫the body-parser or middleware from npm.

131
00:07:40,530 --> 00:07:44,610
‫Again, in this video, I will now install the body-parser,

132
00:07:44,610 --> 00:07:46,440
‫but you don't really need to.

133
00:07:46,440 --> 00:07:49,293
‫You can just use express.raw instead.

134
00:07:51,590 --> 00:07:52,700
‫Npm install

135
00:07:54,480 --> 00:07:55,403
‫body-parser.

136
00:07:58,950 --> 00:08:02,120
‫This probably all sounds a little bit focusing,

137
00:08:02,120 --> 00:08:04,350
‫and I totally understand that,

138
00:08:04,350 --> 00:08:08,050
‫but that's just how the Stripe documentation works

139
00:08:08,890 --> 00:08:10,893
‫and forces us to do it, really.

140
00:08:15,210 --> 00:08:17,100
‫Let's go back here to our route.

141
00:08:17,100 --> 00:08:20,453
‫In this route, we need the body to be in a raw format.

142
00:08:21,460 --> 00:08:25,330
‫We can add that as a middleware here between the route

143
00:08:25,330 --> 00:08:26,673
‫and the final handler.

144
00:08:28,654 --> 00:08:31,013
‫Here we say bodyParser.raw,

145
00:08:34,830 --> 00:08:37,490
‫and we also need to specific here the type

146
00:08:39,450 --> 00:08:43,127
‫just very quick as application/json.

147
00:08:48,130 --> 00:08:52,660
‫We now added this body parsing as a raw body

148
00:08:52,660 --> 00:08:54,183
‫here in this middleware stack.

149
00:08:55,964 --> 00:08:58,150
‫All this will really start to come together

150
00:08:58,150 --> 00:09:00,970
‫once we start implementing this function.

151
00:09:00,970 --> 00:09:02,543
‫Actually let's do that now,

152
00:09:03,820 --> 00:09:05,210
‫so right here.

153
00:09:05,210 --> 00:09:07,100
‫But before we actually do that,

154
00:09:07,100 --> 00:09:09,780
‫let's get rid of all the code that we wrote

155
00:09:09,780 --> 00:09:11,680
‫in order to make it work right now.

156
00:09:11,680 --> 00:09:14,420
‫So, basically this middleware function,

157
00:09:14,420 --> 00:09:16,350
‫we don't need it anymore.

158
00:09:16,350 --> 00:09:18,480
‫Also here in the viewRoutes,

159
00:09:18,480 --> 00:09:21,980
‫we don't need it here anymore either.

160
00:09:21,980 --> 00:09:24,770
‫And then finally in the bookingController,

161
00:09:24,770 --> 00:09:28,153
‫let's also set our URL back to normal.

162
00:09:31,080 --> 00:09:33,180
‫I will just leave all of this here

163
00:09:33,180 --> 00:09:35,233
‫so that you can keep it as a reference.

164
00:09:37,390 --> 00:09:40,863
‫But now the success URL should actually just be this.

165
00:09:43,090 --> 00:09:45,400
‫Basically after a successful booking,

166
00:09:45,400 --> 00:09:48,090
‫we still want to come back to my-tours

167
00:09:48,090 --> 00:09:50,350
‫but without all this query parameters

168
00:09:51,350 --> 00:09:54,580
‫because now it's no longer this function here,

169
00:09:54,580 --> 00:09:57,430
‫which will take care of creating the booking

170
00:09:57,430 --> 00:09:59,770
‫but instead it is this function here,

171
00:09:59,770 --> 00:10:02,060
‫which is of course the one that gets called

172
00:10:02,060 --> 00:10:05,633
‫once Stripe calls our webhook.

173
00:10:07,140 --> 00:10:08,470
‫Let's now implement this.

174
00:10:08,470 --> 00:10:10,140
‫The first thing that we need to do

175
00:10:10,140 --> 00:10:13,763
‫is to rid this Stripe signature out of our headers,

176
00:10:15,780 --> 00:10:19,840
‫so signature and then request.headers

177
00:10:21,500 --> 00:10:26,373
‫and then from there stripe-signature.

178
00:10:28,220 --> 00:10:30,710
‫Basically when Stripe calls our webhook,

179
00:10:30,710 --> 00:10:32,830
‫it will add a header to that request

180
00:10:32,830 --> 00:10:36,280
‫containing a special signature for our webhook.

181
00:10:38,480 --> 00:10:40,700
‫If you're thinking that you're just blindly following

182
00:10:40,700 --> 00:10:42,590
‫what I'm doing here, well, (laughs)

183
00:10:42,590 --> 00:10:45,070
‫that's actually exactly what I did as well

184
00:10:45,070 --> 00:10:47,050
‫from the Stripe documentations.

185
00:10:47,050 --> 00:10:50,320
‫Again, this is really just how Stripe works,

186
00:10:50,320 --> 00:10:52,973
‫and there's nothing we can do against that.

187
00:10:54,350 --> 00:10:57,453
‫Anyway, next up, let's create a Stripe event,

188
00:10:59,310 --> 00:11:03,690
‫so const event equals stripe.

189
00:11:03,690 --> 00:11:07,410
‫For that of course, we need to the Stripe library installed,

190
00:11:07,410 --> 00:11:09,573
‫which we have up here.

191
00:11:12,650 --> 00:11:14,350
‫So, stripe.webhooks.contructEvent.

192
00:11:20,378 --> 00:11:23,210
‫Now here is where finally that body

193
00:11:23,210 --> 00:11:26,520
‫comes into play, so request.body.

194
00:11:26,520 --> 00:11:28,370
‫And remember that this body here

195
00:11:28,370 --> 00:11:30,220
‫needs to be in the raw form,

196
00:11:30,220 --> 00:11:32,083
‫so basically available as a string.

197
00:11:33,130 --> 00:11:36,340
‫Once more, that is why we put that route

198
00:11:36,340 --> 00:11:38,110
‫before all our other routes

199
00:11:38,110 --> 00:11:41,580
‫and especially before the body parser could do its job

200
00:11:41,580 --> 00:11:44,863
‫of converting our body into a JSON object.

201
00:11:46,170 --> 00:11:51,050
‫Then besides that body, for the event, we need a signature,

202
00:11:51,050 --> 00:11:53,370
‫so basically the signature that was sent

203
00:11:53,370 --> 00:11:56,763
‫along with the header, and then finally our webhook secret.

204
00:11:57,710 --> 00:12:00,653
‫Let's get that from here, copy it.

205
00:12:01,585 --> 00:12:05,610
‫Since it's a secret, we should, as always, add it here

206
00:12:05,610 --> 00:12:07,143
‫to our config file,

207
00:12:10,460 --> 00:12:12,737
‫so STRIPE_WEBHOOK_SECRET.

208
00:12:16,650 --> 00:12:19,380
‫And then later of course, don't forget to also add this

209
00:12:19,380 --> 00:12:21,663
‫to our Heroku configuration.

210
00:12:26,100 --> 00:12:27,330
‫Let's now use that.

211
00:12:27,330 --> 00:12:28,767
‫Add process.env.

212
00:12:30,330 --> 00:12:31,830
‫I should have just copied that

213
00:12:35,690 --> 00:12:36,573
‫right here.

214
00:12:37,752 --> 00:12:41,200
‫So, you see, all of this is really to make the process

215
00:12:41,200 --> 00:12:43,450
‫super, super secure.

216
00:12:43,450 --> 00:12:45,970
‫We need all of this data like the signature

217
00:12:45,970 --> 00:12:49,450
‫and also the secret in order to basically validate

218
00:12:49,450 --> 00:12:51,640
‫the data that comes in the body

219
00:12:51,640 --> 00:12:54,433
‫so that no one can actually manipulate that.

220
00:12:55,870 --> 00:12:58,050
‫Now during the creation of this event,

221
00:12:58,050 --> 00:12:59,280
‫there might be some errors,

222
00:12:59,280 --> 00:13:01,420
‫for example if the signature is wrong

223
00:13:01,420 --> 00:13:03,900
‫or if the secret is wrong.

224
00:13:03,900 --> 00:13:07,813
‫And so, let's wrap this into a try-catch block.

225
00:13:16,290 --> 00:13:17,850
‫Okay.

226
00:13:17,850 --> 00:13:19,500
‫Of course, we now need the catch.

227
00:13:22,150 --> 00:13:23,410
‫In case there is an error,

228
00:13:23,410 --> 00:13:26,053
‫we want to send back an error to Stripe,

229
00:13:27,880 --> 00:13:32,450
‫so return res.status 400

230
00:13:33,756 --> 00:13:35,657
‫and then just use send webhook error

231
00:13:40,140 --> 00:13:44,023
‫and then let's just add the error.message.

232
00:13:45,714 --> 00:13:49,220
‫So, it is Stripe who will receive this response here

233
00:13:49,220 --> 00:13:53,230
‫because again it is Stripe who will actually call the URL,

234
00:13:53,230 --> 00:13:56,603
‫so our webhook, which will then call this function.

235
00:13:58,520 --> 00:14:02,420
‫Now we need to of course also declare this event here

236
00:14:02,420 --> 00:14:04,610
‫outside of the try-catch block

237
00:14:04,610 --> 00:14:07,623
‫because otherwise we will not be able to use it down there.

238
00:14:08,660 --> 00:14:13,160
‫So, let event and then reassign down here

239
00:14:13,160 --> 00:14:15,430
‫because remember that the ES6 const

240
00:14:15,430 --> 00:14:17,450
‫and let are block-scoped.

241
00:14:17,450 --> 00:14:20,480
‫And so, this variable would not be available outside

242
00:14:20,480 --> 00:14:21,473
‫of this block.

243
00:14:23,180 --> 00:14:25,830
‫Now let's actually use that event.

244
00:14:25,830 --> 00:14:29,090
‫First off, we need to test if this really is the event

245
00:14:29,090 --> 00:14:29,923
‫that we want.

246
00:14:30,810 --> 00:14:34,240
‫So, we can do event.type

247
00:14:34,240 --> 00:14:38,973
‫is equal to checkout.session.complete.

248
00:14:42,080 --> 00:14:44,370
‫Remember that in our Stripe dashboard,

249
00:14:44,370 --> 00:14:48,090
‫that's exactly the type that we defined here.

250
00:14:48,090 --> 00:14:49,260
‫So, that's the event type.

251
00:14:49,260 --> 00:14:52,183
‫Now we're checking if that is really the event

252
00:14:52,183 --> 00:14:56,287
‫that we are receiving here just to be 100% sure.

253
00:14:56,287 --> 00:14:59,780
‫If it is, we then want to actually use the event

254
00:14:59,780 --> 00:15:02,053
‫to create our booking in our database.

255
00:15:03,860 --> 00:15:06,280
‫Actually let's do that in a separate function

256
00:15:06,280 --> 00:15:08,983
‫and not inside here of all of this mess.

257
00:15:10,517 --> 00:15:12,590
‫For that, I will create a function.

258
00:15:12,590 --> 00:15:13,640
‫Actually let me give it

259
00:15:13,640 --> 00:15:15,990
‫this exact same name, so createBookingCheckout.

260
00:15:17,487 --> 00:15:19,490
‫It was actually a nice name,

261
00:15:19,490 --> 00:15:21,450
‫but now it cannot be a middleware

262
00:15:21,450 --> 00:15:23,250
‫but instead just a regular function.

263
00:15:26,080 --> 00:15:28,823
‫This function will accept the session data.

264
00:15:31,080 --> 00:15:35,310
‫And remember that the session data is exactly this session

265
00:15:35,310 --> 00:15:37,513
‫that we created here in the first place.

266
00:15:41,404 --> 00:15:43,730
‫If this is the correct event,

267
00:15:43,730 --> 00:15:45,743
‫then let's actually call that function,

268
00:15:46,680 --> 00:15:49,500
‫so createBookingCheckout with the session,

269
00:15:49,500 --> 00:15:53,057
‫which is at event.data.object.

270
00:15:57,447 --> 00:15:58,320
‫And then finally,

271
00:15:58,320 --> 00:16:01,333
‫let's just send back some response to Stripe.

272
00:16:02,450 --> 00:16:03,840
‫So, status 200

273
00:16:05,780 --> 00:16:07,480
‫and then let's say some json

274
00:16:10,300 --> 00:16:11,823
‫receive set to true.

275
00:16:13,200 --> 00:16:14,033
‫Makes sense?

276
00:16:16,000 --> 00:16:18,490
‫Once more, all of this code here will run

277
00:16:18,490 --> 00:16:21,390
‫whenever a payment was successful.

278
00:16:21,390 --> 00:16:25,380
‫Stripe will then call our webhook, which is the URL,

279
00:16:25,380 --> 00:16:27,420
‫which is going to call this function.

280
00:16:27,420 --> 00:16:30,600
‫And so, this function receives a body from the request,

281
00:16:30,600 --> 00:16:34,330
‫and then together with the signature and/or webhook secret,

282
00:16:34,330 --> 00:16:37,110
‫creates an event, which will contain the session.

283
00:16:37,110 --> 00:16:39,190
‫And then using that session data,

284
00:16:39,190 --> 00:16:41,963
‫we can create our new booking in the database.

285
00:16:43,987 --> 00:16:45,660
‫And so, that will actually be pretty similar

286
00:16:45,660 --> 00:16:47,143
‫to what we had here before.

287
00:16:48,400 --> 00:16:51,790
‫So, we will need this line of code here again.

288
00:16:51,790 --> 00:16:53,923
‫So, this will also be an async function.

289
00:16:58,497 --> 00:17:00,530
‫And so, this is exactly the same.

290
00:17:00,530 --> 00:17:02,260
‫Now what we need here of course

291
00:17:02,260 --> 00:17:06,690
‫is to get access to the tour, user, and price.

292
00:17:06,690 --> 00:17:10,550
‫But that data once more is stored in that session.

293
00:17:10,550 --> 00:17:12,400
‫So, let's start with the tour.

294
00:17:12,400 --> 00:17:14,780
‫And remember how up here

295
00:17:14,780 --> 00:17:17,100
‫when we first created this handler function,

296
00:17:17,100 --> 00:17:20,040
‫I specified this client_reference_id field

297
00:17:20,040 --> 00:17:22,370
‫and added the tourId to that.

298
00:17:22,370 --> 00:17:23,840
‫Remember that?

299
00:17:23,840 --> 00:17:25,700
‫I did that because, at the time,

300
00:17:25,700 --> 00:17:29,840
‫I already knew that we would need this tour ID a bit later.

301
00:17:29,840 --> 00:17:32,490
‫Now it's that time where we actually need the tour ID

302
00:17:32,490 --> 00:17:35,333
‫in order to be able to create that new booking.

303
00:17:36,732 --> 00:17:38,490
‫And so, now the tour ID that we need

304
00:17:38,490 --> 00:17:41,670
‫is at session dot client's reference ID.

305
00:17:41,670 --> 00:17:44,770
‫So, let's copy this and say

306
00:17:47,870 --> 00:17:48,703
‫session.

307
00:17:49,660 --> 00:17:53,823
‫And of course, here we need to say tour.

308
00:17:55,670 --> 00:17:57,040
‫So, that's the tour ID.

309
00:17:57,040 --> 00:17:59,150
‫Next up, we need the user ID.

310
00:17:59,150 --> 00:18:01,240
‫Now the information that we have in our session

311
00:18:01,240 --> 00:18:03,973
‫about the user is the user's email.

312
00:18:05,630 --> 00:18:07,170
‫And so, now what we need to do

313
00:18:07,170 --> 00:18:10,500
‫is to basically get the user's ID.

314
00:18:10,500 --> 00:18:12,793
‫For that, we will query by the email.

315
00:18:13,720 --> 00:18:16,810
‫That's no problem because the email is also unique.

316
00:18:16,810 --> 00:18:19,353
‫Based on that, we can then find the unique ID.

317
00:18:20,370 --> 00:18:24,183
‫So, const user is await.

318
00:18:25,570 --> 00:18:27,660
‫And I think we already have the user here.

319
00:18:27,660 --> 00:18:28,493
‫No?

320
00:18:29,520 --> 00:18:30,570
‫No, I actually don't.

321
00:18:31,890 --> 00:18:33,290
‫So, let's just do that here.

322
00:18:35,490 --> 00:18:37,973
‫And user here as well.

323
00:18:41,070 --> 00:18:41,903
‫Okay.

324
00:18:41,903 --> 00:18:46,890
‫So, User.findOne and then query via email,

325
00:18:47,990 --> 00:18:51,330
‫which is in session dot,

326
00:18:51,330 --> 00:18:53,780
‫and I believe that's client's email or something.

327
00:18:55,200 --> 00:18:56,200
‫It's customer_email.

328
00:18:59,860 --> 00:19:00,693
‫Okay.

329
00:19:02,070 --> 00:19:04,970
‫But that will then return the entire document,

330
00:19:04,970 --> 00:19:06,910
‫but we want actually the ID.

331
00:19:06,910 --> 00:19:09,780
‫So, let's wrap all of this here in parenthesis

332
00:19:10,730 --> 00:19:14,743
‫and then call the ID on there or actually read the ID.

333
00:19:16,620 --> 00:19:17,960
‫So, that's it.

334
00:19:17,960 --> 00:19:19,233
‫And finally, the price.

335
00:19:22,350 --> 00:19:24,023
‫Where is the price stored?

336
00:19:25,320 --> 00:19:26,833
‫Well, it's here in line_items.

337
00:19:27,880 --> 00:19:30,610
‫That's an array, so at element zero,

338
00:19:30,610 --> 00:19:33,553
‫and then the amount divided by 100.

339
00:19:34,580 --> 00:19:38,210
‫So, we multiplied it here by 100 to get cents,

340
00:19:38,210 --> 00:19:41,590
‫but now of course we want it back in dollars.

341
00:19:41,590 --> 00:19:44,700
‫So, we need to basically divide that back.

342
00:19:44,700 --> 00:19:48,550
‫And so, session.line_items

343
00:19:49,460 --> 00:19:54,460
‫and then the first element dot amount if I'm right.

344
00:19:55,950 --> 00:19:56,783
‫Yeah.

345
00:19:56,783 --> 00:20:01,710
‫So, amount divided by 100.

346
00:20:01,710 --> 00:20:04,010
‫That should actually be it.

347
00:20:04,010 --> 00:20:06,630
‫Let's now commit our changes to the repo

348
00:20:06,630 --> 00:20:08,740
‫and push it to Stripe.

349
00:20:08,740 --> 00:20:12,840
‫So, git add all, of course,

350
00:20:12,840 --> 00:20:16,600
‫and then git commit message

351
00:20:18,090 --> 00:20:21,633
‫Improved stripe implementation,

352
00:20:24,960 --> 00:20:29,960
‫and then git push heroku master.

353
00:20:31,190 --> 00:20:33,273
‫Once more, this will take some time.

354
00:20:33,273 --> 00:20:35,263
‫I'll see you when that's done.

355
00:20:36,200 --> 00:20:37,033
‫All right.

356
00:20:37,033 --> 00:20:40,323
‫Now don't forget to set that new environment variable.

357
00:20:41,610 --> 00:20:46,610
‫So, that's heroku config colon set,

358
00:20:46,750 --> 00:20:49,433
‫and then simply copy it from here.

359
00:20:53,590 --> 00:20:54,720
‫Okay.

360
00:20:54,720 --> 00:20:56,800
‫That then restarts the application.

361
00:20:56,800 --> 00:20:58,173
‫And that's it.

362
00:20:59,570 --> 00:21:02,723
‫So, let's now actually go ahead and test it.

363
00:21:04,980 --> 00:21:05,813
‫All right.

364
00:21:07,050 --> 00:21:09,480
‫We are still here in our application.

365
00:21:09,480 --> 00:21:12,883
‫Let's see which tours Laura has already booked.

366
00:21:14,100 --> 00:21:15,370
‫She has the Forest Hiker.

367
00:21:15,370 --> 00:21:19,823
‫That booking was still done using the old method.

368
00:21:21,050 --> 00:21:24,240
‫But that old method now no longer works.

369
00:21:24,240 --> 00:21:27,047
‫Now if we do another booking and it works,

370
00:21:27,047 --> 00:21:29,490
‫well, then that's going to mean

371
00:21:29,490 --> 00:21:32,773
‫that of course our new implementation works.

372
00:21:34,730 --> 00:21:35,780
‫Let's test that here.

373
00:21:39,760 --> 00:21:41,493
‫As always, 4242.

374
00:21:50,420 --> 00:21:51,683
‫Now let's wait for it.

375
00:21:52,730 --> 00:21:55,740
‫Well, that apparently didn't go so well

376
00:21:55,740 --> 00:21:58,520
‫because otherwise our second new tour

377
00:21:58,520 --> 00:22:00,743
‫should already be here in our bookings.

378
00:22:02,230 --> 00:22:04,203
‫Let's see here in our dashboard.

379
00:22:05,860 --> 00:22:06,983
‫If we now reload this,

380
00:22:12,150 --> 00:22:15,893
‫then we actually see that there was a successful event.

381
00:22:17,407 --> 00:22:20,320
‫So, that's the event that we just created

382
00:22:20,320 --> 00:22:23,170
‫and which sent this body here

383
00:22:23,170 --> 00:22:25,380
‫and then received this response.

384
00:22:25,380 --> 00:22:27,560
‫So, this receive set to true

385
00:22:27,560 --> 00:22:30,663
‫is exactly what we did here in our code,

386
00:22:31,670 --> 00:22:32,633
‫so this here.

387
00:22:34,060 --> 00:22:36,000
‫So, that's the response that we sent

388
00:22:36,000 --> 00:22:39,770
‫and the body that we got in was all of this data.

389
00:22:39,770 --> 00:22:42,810
‫And so, we can see here the session with the price,

390
00:22:42,810 --> 00:22:46,460
‫with the email, with the tour.

391
00:22:46,460 --> 00:22:49,483
‫And so, I'm not sure why it didn't work.

392
00:22:51,000 --> 00:22:53,163
‫So, let's just quickly reload this here.

393
00:22:55,780 --> 00:22:59,050
‫So, actually our Stripe implementation should be correct,

394
00:22:59,050 --> 00:23:02,013
‫but, for some reason, our new booking was not created.

395
00:23:03,120 --> 00:23:05,020
‫Let's check that also here in Compass.

396
00:23:07,460 --> 00:23:09,970
‫And indeed, it's not there.

397
00:23:09,970 --> 00:23:12,123
‫So, let's go back to our code here.

398
00:23:13,410 --> 00:23:17,360
‫Oh and one error that I see right away is here.

399
00:23:17,360 --> 00:23:20,393
‫So, it should be completed like this.

400
00:23:22,090 --> 00:23:24,480
‫So, that's a stupid mistake.

401
00:23:24,480 --> 00:23:26,950
‫Let's just see if there might be another error

402
00:23:26,950 --> 00:23:30,050
‫up here in createBookingCheckout.

403
00:23:30,050 --> 00:23:30,883
‫Here we have

404
00:23:32,750 --> 00:23:33,583
‫line_items.

405
00:23:33,583 --> 00:23:35,093
‫Let's see if that's correct.

406
00:23:36,110 --> 00:23:38,170
‫And yeah, it seems to be.

407
00:23:38,170 --> 00:23:41,123
‫We can also confirm that here again in our Stripe.

408
00:23:43,110 --> 00:23:45,290
‫Actually here it's called display_items.

409
00:23:46,590 --> 00:23:47,423
‫That's weird.

410
00:23:48,367 --> 00:23:52,140
‫Just to make sure, let's also call it display_items

411
00:23:52,140 --> 00:23:54,363
‫here in our code right here.

412
00:23:55,980 --> 00:23:57,580
‫Now another thing that I noticed

413
00:23:58,750 --> 00:24:00,350
‫now as I took another look here

414
00:24:00,350 --> 00:24:03,510
‫is that we still have this image hardcoded

415
00:24:03,510 --> 00:24:05,763
‫to this other natours.dev.

416
00:24:07,587 --> 00:24:11,380
‫Now let's actually fix that because at this point of course,

417
00:24:11,380 --> 00:24:14,580
‫our website is already live and deployed.

418
00:24:14,580 --> 00:24:16,600
‫And so, we can basically replace that

419
00:24:16,600 --> 00:24:18,100
‫with the same as we have here.

420
00:24:20,900 --> 00:24:23,430
‫So, we use this part here many times.

421
00:24:23,430 --> 00:24:25,480
‫And so, it's time to use that again here.

422
00:24:32,672 --> 00:24:33,505
‫Yeah.

423
00:24:33,505 --> 00:24:35,353
‫Let's try to redeploy this.

424
00:24:36,380 --> 00:24:38,113
‫So, git add all again.

425
00:24:40,420 --> 00:24:42,070
‫And let's just call this here

426
00:24:42,070 --> 00:24:44,430
‫Improved stripe implementation two.

427
00:24:44,430 --> 00:24:47,693
‫And then push it again to Heroku.

428
00:24:51,580 --> 00:24:52,560
‫Okay.

429
00:24:52,560 --> 00:24:54,253
‫Let's try that one more time.

430
00:24:55,830 --> 00:24:57,023
‫Let's go back here.

431
00:25:00,630 --> 00:25:04,063
‫Now let's try to book again to Park Camper.

432
00:25:15,760 --> 00:25:16,683
‫All right.

433
00:25:17,920 --> 00:25:21,530
‫You ought to see the image popping up here on the left side.

434
00:25:21,530 --> 00:25:24,200
‫That means that our new image integration

435
00:25:24,200 --> 00:25:25,753
‫also worked just fine.

436
00:25:27,220 --> 00:25:28,283
‫Now it's processing.

437
00:25:29,382 --> 00:25:31,380
‫Ah now it is here.

438
00:25:31,380 --> 00:25:32,320
‫Great.

439
00:25:32,320 --> 00:25:33,533
‫That's beautiful.

440
00:25:34,420 --> 00:25:36,850
‫Now we really have a secure

441
00:25:36,850 --> 00:25:39,940
‫and way more professional Stripe implementation

442
00:25:39,940 --> 00:25:41,173
‫in our application.

443
00:25:42,070 --> 00:25:43,520
‫That's great.

444
00:25:43,520 --> 00:25:45,570
‫Of course, if you reload here,

445
00:25:45,570 --> 00:25:49,500
‫then you should see this new event here,

446
00:25:49,500 --> 00:25:52,050
‫so this new call to our webhook,

447
00:25:52,050 --> 00:25:54,593
‫which of course again was successful.

448
00:25:55,840 --> 00:25:57,690
‫That's just great.

449
00:25:57,690 --> 00:26:00,740
‫Now there's just one final thing that I want to do,

450
00:26:00,740 --> 00:26:04,420
‫which is to basically give the user some feedback

451
00:26:04,420 --> 00:26:06,980
‫in form of one of these green messages

452
00:26:06,980 --> 00:26:09,123
‫that we use also for example in the login.

453
00:26:10,650 --> 00:26:12,930
‫Right now our application doesn't really give

454
00:26:12,930 --> 00:26:16,476
‫any kind of feedback when a new tour was booked.

455
00:26:16,476 --> 00:26:18,650
‫Now I want to change that.

456
00:26:18,650 --> 00:26:21,900
‫However, doing this is not really straightforward

457
00:26:21,900 --> 00:26:23,990
‫because remember that these messages

458
00:26:23,990 --> 00:26:26,750
‫are actually displayed by JavaScript.

459
00:26:26,750 --> 00:26:30,280
‫So, in the other cases, we did an HTTP call to our API.

460
00:26:30,280 --> 00:26:33,070
‫And then when that was done, we used JavaScript

461
00:26:33,070 --> 00:26:34,840
‫to display some kind of message.

462
00:26:34,840 --> 00:26:36,970
‫But now we do not do it this way.

463
00:26:36,970 --> 00:26:40,710
‫And so, the message should already be somewhere in the HTML

464
00:26:40,710 --> 00:26:42,380
‫as soon as the page loads

465
00:26:42,380 --> 00:26:45,400
‫so that then our JavaScript can pick that message up

466
00:26:45,400 --> 00:26:49,070
‫from the HTML and display it nicely up there

467
00:26:49,070 --> 00:26:50,463
‫in one of these banners.

468
00:26:51,610 --> 00:26:54,510
‫And so, the way I'm going to put these alerts

469
00:26:54,510 --> 00:26:58,223
‫in the HTML is once more by using a data property.

470
00:26:59,450 --> 00:27:03,000
‫Let's start by implementing this feature right there

471
00:27:03,000 --> 00:27:04,363
‫in our main template.

472
00:27:06,610 --> 00:27:09,273
‫That's here in views, base.

473
00:27:11,160 --> 00:27:13,630
‫I will actually add that alert message

474
00:27:13,630 --> 00:27:15,663
‫right onto the body element.

475
00:27:17,110 --> 00:27:19,963
‫Here we will have a data alert property,

476
00:27:21,860 --> 00:27:24,000
‫which should actually only be set

477
00:27:24,000 --> 00:27:26,563
‫if the alert variable is available here.

478
00:27:27,480 --> 00:27:31,460
‫So, let's use ES6, so a template string,

479
00:27:31,460 --> 00:27:35,060
‫and say if there is an alert,

480
00:27:35,060 --> 00:27:38,713
‫then use alert here, and else, an empty string.

481
00:27:39,980 --> 00:27:43,370
‫And so, this alert here will be the alert message

482
00:27:43,370 --> 00:27:47,230
‫that JavaScript will then pick up and display on the page.

483
00:27:47,230 --> 00:27:50,230
‫Now how does this alert message then actually end up

484
00:27:50,230 --> 00:27:52,513
‫as an alert variable here in our template?

485
00:27:53,360 --> 00:27:56,448
‫Well, I came up with a solution that is reusable

486
00:27:56,448 --> 00:27:59,250
‫so that we can use all over our application.

487
00:27:59,250 --> 00:28:01,840
‫That is that on the query string,

488
00:28:01,840 --> 00:28:03,890
‫we will add some alert keyword

489
00:28:03,890 --> 00:28:05,820
‫and then we will have a middleware,

490
00:28:05,820 --> 00:28:08,560
‫which will take that keyword from the URL

491
00:28:08,560 --> 00:28:10,910
‫and, according to the keyword that we put there,

492
00:28:10,910 --> 00:28:15,050
‫will then put a whole alert message on response.locals.

493
00:28:15,050 --> 00:28:19,000
‫And so, remember that everything that's on response.locals

494
00:28:19,000 --> 00:28:22,483
‫is then available as a variable in all of our templates.

495
00:28:23,450 --> 00:28:25,630
‫So, we actually used that before

496
00:28:25,630 --> 00:28:27,563
‫in our authController, I believe.

497
00:28:29,480 --> 00:28:32,567
‫Very quickly, let me show that to you.

498
00:28:33,530 --> 00:28:37,060
‫Right here, we said response.local.user

499
00:28:37,060 --> 00:28:39,074
‫and put the current user there.

500
00:28:39,074 --> 00:28:41,720
‫Then automatically in all templates,

501
00:28:41,720 --> 00:28:44,283
‫we have access to that user variable.

502
00:28:47,430 --> 00:28:50,070
‫So, let's now implement what I just said

503
00:28:50,070 --> 00:28:52,597
‫and starting with the URL.

504
00:28:54,330 --> 00:28:57,540
‫What I'm gonna do here is to actually add that query string

505
00:28:57,540 --> 00:28:59,097
‫here to the success URL.

506
00:28:59,970 --> 00:29:04,573
‫Here, I will say alert equal booking.

507
00:29:05,970 --> 00:29:10,310
‫Now I could, in all other URLS, also add some alert

508
00:29:10,310 --> 00:29:12,863
‫and then with a different keyword here, of course.

509
00:29:14,350 --> 00:29:18,100
‫And we will just do it here really for this booking.

510
00:29:18,100 --> 00:29:21,793
‫But again I created a kind of reusable solution here.

511
00:29:23,340 --> 00:29:27,470
‫Anyway, now in our routes, we need basically a middleware,

512
00:29:27,470 --> 00:29:29,920
‫which will run for all the requests.

513
00:29:29,920 --> 00:29:32,270
‫And it's that middleware, which will pick up the alert

514
00:29:32,270 --> 00:29:35,240
‫from the query string and put a alert message

515
00:29:35,240 --> 00:29:37,453
‫onto our response.locals.

516
00:29:41,457 --> 00:29:42,624
‫So, router.use

517
00:29:45,040 --> 00:29:48,233
‫viewsController.alerts.

518
00:29:50,290 --> 00:29:52,320
‫And so, this is a middleware function,

519
00:29:52,320 --> 00:29:56,200
‫which will basically run for each and every single request

520
00:29:56,200 --> 00:29:58,130
‫that's coming into this router,

521
00:29:58,130 --> 00:30:01,063
‫so basically for all the requests to our website.

522
00:30:02,370 --> 00:30:04,870
‫Now let's actually create that middleware

523
00:30:04,870 --> 00:30:06,020
‫in our viewsController.

524
00:30:10,460 --> 00:30:12,380
‫So, exports.alerts

525
00:30:14,480 --> 00:30:17,283
‫request, response, and next.

526
00:30:19,650 --> 00:30:20,730
‫And so, the alert

527
00:30:22,760 --> 00:30:26,300
‫is request.query.alert.

528
00:30:26,300 --> 00:30:29,873
‫And so, let's just use this structuring here once more.

529
00:30:32,020 --> 00:30:36,553
‫And then let's say if alert is equals to booking,

530
00:30:39,030 --> 00:30:42,653
‫so the alert that we put right here in the query string,

531
00:30:44,670 --> 00:30:46,070
‫well, then in that case,

532
00:30:46,070 --> 00:30:50,970
‫let's say response.locals.alert

533
00:30:52,830 --> 00:30:53,780
‫will be

534
00:30:56,910 --> 00:30:57,970
‫your booking

535
00:30:59,850 --> 00:31:01,023
‫was successful,

536
00:31:03,790 --> 00:31:06,883
‫please check your email for a confirmation.

537
00:31:10,330 --> 00:31:13,090
‫And we should also add some other phrase,

538
00:31:13,090 --> 00:31:17,960
‫which is this one, if your booking doesn't,

539
00:31:24,070 --> 00:31:27,743
‫select this, doesn't show up here immediately,

540
00:31:33,270 --> 00:31:34,523
‫please come back later.

541
00:31:36,140 --> 00:31:37,230
‫And this last part

542
00:31:37,230 --> 00:31:39,920
‫is because Stripe does very specifically say

543
00:31:39,920 --> 00:31:43,620
‫in their documentation that sometimes the webhook is called

544
00:31:43,620 --> 00:31:46,880
‫a little bit after the success URL is called.

545
00:31:46,880 --> 00:31:49,810
‫In that case, that success URL would then show

546
00:31:49,810 --> 00:31:52,677
‫all of the current tours, but only after that,

547
00:31:52,677 --> 00:31:54,300
‫the webhook would be called

548
00:31:54,300 --> 00:31:57,270
‫and the tour would be created in our database.

549
00:31:57,270 --> 00:32:00,040
‫Therefore, the new booking would not show up right away

550
00:32:00,040 --> 00:32:01,953
‫on the My Bookings page.

551
00:32:02,850 --> 00:32:06,220
‫But of course, everything still worked well in that case.

552
00:32:06,220 --> 00:32:09,583
‫And so, I simply reload, but later we'll fix that problem.

553
00:32:12,340 --> 00:32:15,080
‫Now we just need to call the next middleware.

554
00:32:15,080 --> 00:32:17,160
‫And that's actually it.

555
00:32:17,160 --> 00:32:21,390
‫Again, we only did this here for alert equal to booking,

556
00:32:21,390 --> 00:32:24,090
‫but we could now use this all over the place

557
00:32:24,090 --> 00:32:27,070
‫in our website by setting different alert keywords

558
00:32:27,070 --> 00:32:28,982
‫and query strings.

559
00:32:28,982 --> 00:32:33,982
‫With this, we put this message here onto res.locals.alert.

560
00:32:35,600 --> 00:32:38,940
‫Again, our base template will then pick that up

561
00:32:38,940 --> 00:32:42,320
‫and display it here into this data alert property.

562
00:32:42,320 --> 00:32:46,440
‫And so, all that is left to do now is to go to our index.js

563
00:32:46,440 --> 00:32:49,890
‫and read the alert from here and then display it.

564
00:32:49,890 --> 00:32:52,100
‫And so, that should be fairly easy.

565
00:32:52,100 --> 00:32:56,230
‫Here in public, let's actually do it right in the index.

566
00:32:56,230 --> 00:33:00,260
‫And the first thing is that we actually need to import

567
00:33:00,260 --> 00:33:01,343
‫the alerts function.

568
00:33:06,480 --> 00:33:08,160
‫That's not an app.

569
00:33:08,160 --> 00:33:09,343
‫It's here in index.

570
00:33:10,920 --> 00:33:12,090
‫Okay.

571
00:33:12,090 --> 00:33:15,883
‫And then down here, let's basically read that alert.

572
00:33:17,290 --> 00:33:22,133
‫So, const alertMessage, let's say,

573
00:33:23,250 --> 00:33:25,320
‫is document.querySelector,

574
00:33:28,742 --> 00:33:31,327
‫then the body element, dot dataset.alert.

575
00:33:35,350 --> 00:33:37,673
‫And so, only if there is an alert, of course,

576
00:33:39,760 --> 00:33:42,020
‫then show the alert

577
00:33:43,160 --> 00:33:44,250
‫with success

578
00:33:45,840 --> 00:33:48,000
‫and the alert message.

579
00:33:48,000 --> 00:33:50,640
‫And now this one small thing that I want to do

580
00:33:50,640 --> 00:33:54,630
‫is to change a little bit this showAlert function here

581
00:33:54,630 --> 00:33:57,210
‫because we actually have a lot of text now.

582
00:33:57,210 --> 00:33:59,780
‫And the standard time that the alert is shown

583
00:33:59,780 --> 00:34:03,163
‫would not be enough to actually read all the text.

584
00:34:04,210 --> 00:34:06,880
‫So, you see here that after five seconds,

585
00:34:06,880 --> 00:34:08,373
‫the alert is hidden.

586
00:34:10,126 --> 00:34:11,760
‫Let's actually allow the user to specify

587
00:34:11,760 --> 00:34:14,253
‫the amount of seconds that the alert is shown.

588
00:34:16,810 --> 00:34:20,320
‫We will do that as a default of five seconds.

589
00:34:20,320 --> 00:34:24,810
‫Here, we then simply do time times 1,000

590
00:34:24,810 --> 00:34:26,483
‫to convert it to milliseconds.

591
00:34:27,976 --> 00:34:30,690
‫Like this, all the functions will work everywhere

592
00:34:30,690 --> 00:34:32,270
‫with five seconds.

593
00:34:32,270 --> 00:34:34,790
‫Let's actually make it seven seconds

594
00:34:34,790 --> 00:34:36,600
‫if we don't specify anything.

595
00:34:36,600 --> 00:34:39,980
‫But if we want, we can then override this seven.

596
00:34:39,980 --> 00:34:42,040
‫And so, I will that now here

597
00:34:42,040 --> 00:34:45,370
‫and actually put it 20 seconds on the screen.

598
00:34:45,370 --> 00:34:46,203
‫All right.

599
00:34:47,360 --> 00:34:49,240
‫I think that should be it.

600
00:34:49,240 --> 00:34:51,060
‫I hope that made sense.

601
00:34:51,060 --> 00:34:53,993
‫Let's now just very quickly compile our bundle.

602
00:34:55,360 --> 00:35:00,343
‫That's npm run build, then tap autocomplete.

603
00:35:03,480 --> 00:35:05,990
‫That takes a little bit of time as well.

604
00:35:05,990 --> 00:35:07,373
‫But now it's done.

605
00:35:12,030 --> 00:35:14,340
‫Let's now deploy it one last time

606
00:35:15,580 --> 00:35:17,083
‫hoping that it works actually.

607
00:35:18,250 --> 00:35:19,083
‫So, git commit.

608
00:35:25,840 --> 00:35:27,513
‫So, Stripe messages.

609
00:35:29,670 --> 00:35:34,670
‫And one last time, git push heroku master.

610
00:35:37,451 --> 00:35:41,403
‫Let's now test it by buying yet another tour here.

611
00:35:42,830 --> 00:35:44,963
‫Let's get the City Wanderer this time.

612
00:35:46,490 --> 00:35:49,683
‫Oh I just see that there is a message already here.

613
00:35:50,810 --> 00:35:51,783
‫That's not good.

614
00:35:54,530 --> 00:35:58,500
‫And you see that it disappeared after 20 seconds.

615
00:35:58,500 --> 00:36:00,240
‫So, it seems like now, by default,

616
00:36:00,240 --> 00:36:02,993
‫it will always put this alert class here.

617
00:36:06,028 --> 00:36:06,861
‫(laughs)

618
00:36:06,861 --> 00:36:07,694
‫Yeah.

619
00:36:07,694 --> 00:36:09,990
‫That's because here it should be alertMessage

620
00:36:09,990 --> 00:36:11,063
‫and not just alert.

621
00:36:12,810 --> 00:36:16,800
‫But anyway, let's now just test

622
00:36:16,800 --> 00:36:20,433
‫if the message actually is correct when we book the tour.

623
00:36:24,410 --> 00:36:25,243
‫Okay.

624
00:36:32,470 --> 00:36:34,880
‫Now let's wait for it.

625
00:36:34,880 --> 00:36:36,330
‫Here we go.

626
00:36:36,330 --> 00:36:39,163
‫Indeed, there is our message.

627
00:36:40,130 --> 00:36:41,460
‫So, beautiful.

628
00:36:41,460 --> 00:36:44,420
‫Also, our tour shows up here.

629
00:36:44,420 --> 00:36:48,510
‫And you see that it really stays here for a lot of time.

630
00:36:48,510 --> 00:36:49,853
‫So, that also works.

631
00:36:51,532 --> 00:36:52,832
‫Let's just very quickly...

632
00:36:55,840 --> 00:36:59,383
‫And first, we actually need to rebuild the bundle here.

633
00:37:03,877 --> 00:37:07,170
‫Then we can add everything to our staging area,

634
00:37:13,580 --> 00:37:18,490
‫Message alert bug fix.

635
00:37:18,490 --> 00:37:19,670
‫So, these are some (laughs)

636
00:37:19,670 --> 00:37:23,500
‫really professional-sounding messages here already.

637
00:37:23,500 --> 00:37:26,313
‫Now one final push to Heroku.

638
00:37:29,670 --> 00:37:32,580
‫Now when we load our page,

639
00:37:32,580 --> 00:37:34,740
‫we should see no alert message.

640
00:37:34,740 --> 00:37:37,250
‫And indeed, now everything is clean.

641
00:37:37,250 --> 00:37:40,470
‫And so, I can now say that at least for now,

642
00:37:40,470 --> 00:37:42,977
‫this project is really finished.

643
00:37:42,977 --> 00:37:46,490
‫Once more, great job, congratulations,

644
00:37:46,490 --> 00:37:51,100
‫and well done for probably being one of the few people

645
00:37:51,100 --> 00:37:54,350
‫who actually are making it all the way to the end

646
00:37:54,350 --> 00:37:58,370
‫of the project and really building this beautiful website

647
00:37:58,370 --> 00:38:01,780
‫and also API that you can now put on your portfolio

648
00:38:01,780 --> 00:38:02,923
‫and show the world.

