1
00:00:00,000 --> 00:00:01,000
So let's now work

2
00:00:01,000 --> 00:00:04,000
on that Meal Details page here.

3
00:00:04,000 --> 00:00:07,000
For that I'll go to this meals folder

4
00:00:07,000 --> 00:00:09,000
and then there this dynamic segment folder,

5
00:00:09,000 --> 00:00:13,000
this mealSlug folder, and then there this page.js file

6
00:00:13,000 --> 00:00:16,000
because that is the component responsible

7
00:00:16,000 --> 00:00:18,000
for outputting the details about a meal.

8
00:00:19,000 --> 00:00:22,000
Now here I again then want to output a fragment

9
00:00:22,000 --> 00:00:23,000
because I want to have a header

10
00:00:23,000 --> 00:00:26,000
and next to that the main section

11
00:00:26,000 --> 00:00:28,000
as we had it on many other pages as well.

12
00:00:28,000 --> 00:00:31,000
Now, I also prepared some styles for this page.

13
00:00:31,000 --> 00:00:35,000
So attached you find a page.module.css file,

14
00:00:35,000 --> 00:00:38,000
which you should store next to this page.js file.

15
00:00:39,000 --> 00:00:42,000
And then we can import our classes

16
00:00:42,000 --> 00:00:45,000
from that page.module.css file

17
00:00:48,000 --> 00:00:51,000
so that then we can, for example, add a class here

18
00:00:51,000 --> 00:00:55,000
to this header, a class named header.

19
00:00:57,000 --> 00:01:02,000
In that header, I then want to have a couple of things.

20
00:01:02,000 --> 00:01:04,000
For example, I wanna have a div in there

21
00:01:04,000 --> 00:01:09,000
with a class of image, which will then be responsible

22
00:01:09,000 --> 00:01:13,000
for outputting the meal image that belongs to a meal.

23
00:01:13,000 --> 00:01:15,000
And we will output that image with help

24
00:01:15,000 --> 00:01:17,000
of the image component,

25
00:01:17,000 --> 00:01:20,000
which is provided by NextJS imported

26
00:01:20,000 --> 00:01:22,000
from the next/image package.

27
00:01:24,000 --> 00:01:26,000
Now we'll configure this image later

28
00:01:26,000 --> 00:01:29,000
because at the moment we don't have the meal yet.

29
00:01:29,000 --> 00:01:31,000
We'll add the logic for that soon though.

30
00:01:31,000 --> 00:01:35,000
The only thing I want to add already is this fill prop here,

31
00:01:35,000 --> 00:01:38,000
since again, I won't know the exact dimensions

32
00:01:38,000 --> 00:01:40,000
of the image file yet,

33
00:01:40,000 --> 00:01:43,000
and therefore, I'll use this fill prop as a fallback

34
00:01:43,000 --> 00:01:45,000
or as a solution.

35
00:01:47,000 --> 00:01:50,000
Then below that, I'll add another div

36
00:01:50,000 --> 00:01:53,000
with a class of headerText,

37
00:01:58,000 --> 00:02:02,000
written like this, not with a dash, but instead camel case.

38
00:02:02,000 --> 00:02:07,000
That's how the CSS class name in the CSS file is named.

39
00:02:07,000 --> 00:02:10,000
In there, you should then add a h1 element,

40
00:02:10,000 --> 00:02:13,000
where we'll later output the meal title.

41
00:02:13,000 --> 00:02:15,000
And below that a paragraph,

42
00:02:15,000 --> 00:02:19,000
which receives another CSS class, a class of creator,

43
00:02:19,000 --> 00:02:22,000
where I want to output the text by

44
00:02:22,000 --> 00:02:27,000
and then the name of the creator wrapped into a link.

45
00:02:27,000 --> 00:02:30,000
And here I'll use the regular anchor element

46
00:02:30,000 --> 00:02:33,000
because this should actually be a link that allows us

47
00:02:33,000 --> 00:02:35,000
to send an email to that creator.

48
00:02:36,000 --> 00:02:39,000
Therefore, the actual href value

49
00:02:39,000 --> 00:02:42,000
will be a dynamically generated string

50
00:02:42,000 --> 00:02:45,000
using this string literal syntax

51
00:02:45,000 --> 00:02:47,000
with those backticks here,

52
00:02:47,000 --> 00:02:48,000
where I'll say mailto:

53
00:02:49,000 --> 00:02:51,000
and then here I'll inject

54
00:02:51,000 --> 00:02:54,000
that email address once we have it later.

55
00:02:56,000 --> 00:02:58,000
And that's how we can set up a link

56
00:02:58,000 --> 00:03:00,000
that will open the Mail program,

57
00:03:00,000 --> 00:03:03,000
so that users can send an email to that person.

58
00:03:05,000 --> 00:03:07,000
Below that, we can add another paragraph,

59
00:03:07,000 --> 00:03:10,000
which also receives a class,

60
00:03:10,000 --> 00:03:13,000
and here the class should be the summary class,

61
00:03:13,000 --> 00:03:16,000
where I want to output the short summary text

62
00:03:16,000 --> 00:03:17,000
that summarizes a meal.

63
00:03:19,000 --> 00:03:21,000
And that's then this header.

64
00:03:21,000 --> 00:03:23,000
Of course, a lot of data is missing,

65
00:03:23,000 --> 00:03:24,000
but we'll take care of that soon.

66
00:03:26,000 --> 00:03:28,000
Now in that main section,

67
00:03:28,000 --> 00:03:31,000
I simply wanna output one paragraph,

68
00:03:31,000 --> 00:03:35,000
which receives a CSS class name called instructions.

69
00:03:37,000 --> 00:03:40,000
And then here, I want to output the instructions

70
00:03:40,000 --> 00:03:43,000
that are stored for every meal.

71
00:03:43,000 --> 00:03:47,000
And those should actually be output as HTML code,

72
00:03:47,000 --> 00:03:49,000
which can be achieved in React

73
00:03:49,000 --> 00:03:54,000
by targeting the dangerouslySetInnerHTML prop on an element.

74
00:03:56,000 --> 00:03:59,000
And it's called like this because you open yourself up

75
00:03:59,000 --> 00:04:04,000
to cross-site scripting attacks when outputting content

76
00:04:04,000 --> 00:04:08,000
as HTML content, at least if you're not validating it.

77
00:04:09,000 --> 00:04:13,000
Now this prop then wants a object as a value,

78
00:04:13,000 --> 00:04:18,000
and that object should have an __html property,

79
00:04:18,000 --> 00:04:21,000
which then contains the actual HTML code

80
00:04:21,000 --> 00:04:23,000
that should be output on the screen.

81
00:04:23,000 --> 00:04:25,000
Now we'll get that code later

82
00:04:25,000 --> 00:04:27,000
from that meal once we fetched it,

83
00:04:27,000 --> 00:04:29,000
but that's how we'll output it on the screen.

84
00:04:32,000 --> 00:04:35,000
So that this is in the end our Meal Details page

85
00:04:35,000 --> 00:04:38,000
without the data that we wanna output.

86
00:04:38,000 --> 00:04:40,000
Now, in order to have some data

87
00:04:40,000 --> 00:04:43,000
to output on that Meal Detail screen,

88
00:04:43,000 --> 00:04:46,000
we should go back to the meals.js file in the lib folder,

89
00:04:47,000 --> 00:04:50,000
and there we can export another async function

90
00:04:50,000 --> 00:04:52,000
that could be called getMeal.

91
00:04:53,000 --> 00:04:57,000
And here I then expect to get the slug of the meal

92
00:04:57,000 --> 00:05:00,000
that identifies the meal that should be fetched.

93
00:05:01,000 --> 00:05:06,000
Well, and then we simply wanna return db.prepare,

94
00:05:06,000 --> 00:05:11,000
and then SELECT all columns FROM the meals table

95
00:05:11,000 --> 00:05:14,000
WHERE the slug field

96
00:05:14,000 --> 00:05:16,000
is equal to the slug we're getting here.

97
00:05:18,000 --> 00:05:21,000
Now you could now add it like this,

98
00:05:21,000 --> 00:05:23,000
but that would be insecure.

99
00:05:23,000 --> 00:05:25,000
That opens yourself up to SQL injection.

100
00:05:26,000 --> 00:05:28,000
Instead, you should use a question mark

101
00:05:28,000 --> 00:05:31,000
as a placeholder here,

102
00:05:31,000 --> 00:05:33,000
and then call the get method here

103
00:05:33,000 --> 00:05:36,000
since I only want to get a single record,

104
00:05:37,000 --> 00:05:40,000
and then you pass the value that should be inserted

105
00:05:40,000 --> 00:05:43,000
for that placeholder to get.

106
00:05:43,000 --> 00:05:47,000
In this case that's slug, which we get here.

107
00:05:47,000 --> 00:05:51,000
Under the hood, this better-sqlite3 package we're using here

108
00:05:51,000 --> 00:05:55,000
will then protect you against SQL injection attacks.

109
00:05:55,000 --> 00:05:57,000
That's why you should add dynamic values

110
00:05:57,000 --> 00:06:00,000
into your statements like this.

111
00:06:00,000 --> 00:06:02,000
So that should then return a meal.

112
00:06:03,000 --> 00:06:08,000
So we can therefore go back to this Meals Detail page here,

113
00:06:08,000 --> 00:06:11,000
and now in there, call getMeal,

114
00:06:14,000 --> 00:06:16,000
and import that from that lib folder,

115
00:06:16,000 --> 00:06:17,000
and the meals.js file there.

116
00:06:20,000 --> 00:06:22,000
Here, we'll then get back a meal,

117
00:06:22,000 --> 00:06:24,000
which we can then use down there

118
00:06:24,000 --> 00:06:27,000
to well populate this JSX code,

119
00:06:28,000 --> 00:06:31,000
but getMeal of course needs that slug.

120
00:06:32,000 --> 00:06:37,000
And that slug is simply that part that's encoded in the URL

121
00:06:37,000 --> 00:06:40,000
that is caught with help of this placeholder here,

122
00:06:40,000 --> 00:06:42,000
this mealSlug placeholder.

123
00:06:43,000 --> 00:06:46,000
So how do we then get access to that concrete value

124
00:06:46,000 --> 00:06:48,000
that's part of the URL?

125
00:06:49,000 --> 00:06:52,000
With help of the props we are receiving on this page.

126
00:06:52,000 --> 00:06:57,000
I mentioned before that NextJS is passing some special props

127
00:06:57,000 --> 00:06:59,000
to these special files

128
00:06:59,000 --> 00:07:03,000
or to these components in those special files.

129
00:07:03,000 --> 00:07:05,000
And for example, every component

130
00:07:05,000 --> 00:07:08,000
that's stored in a page.js file

131
00:07:08,000 --> 00:07:11,000
will receive a special params prop,

132
00:07:11,000 --> 00:07:14,000
which you can, therefore, destructure.

133
00:07:14,000 --> 00:07:18,000
And this params prop will then itself contain an object

134
00:07:18,000 --> 00:07:22,000
as a value where any dynamic path segment

135
00:07:22,000 --> 00:07:25,000
that's configured for this route will be stored

136
00:07:25,000 --> 00:07:27,000
as a key-value pair.

137
00:07:27,000 --> 00:07:29,000
And this name you chose here

138
00:07:29,000 --> 00:07:33,000
between those square brackets will be used as a key

139
00:07:34,000 --> 00:07:38,000
and the actual value encoded in the URL will be used

140
00:07:38,000 --> 00:07:40,000
as a value for that key.

141
00:07:40,000 --> 00:07:43,000
And it is that value I need to get to look

142
00:07:43,000 --> 00:07:45,000
for that value in the database.

143
00:07:47,000 --> 00:07:51,000
So therefore, we can now pass params.mealsSlug to getMeal,

144
00:07:53,000 --> 00:07:55,000
and that will be that identifier

145
00:07:55,000 --> 00:07:58,000
that hopefully allows us to fetch a meal from the database.

146
00:08:00,000 --> 00:08:01,000
Now to see whether that worked,

147
00:08:01,000 --> 00:08:06,000
let's try outputting a title here with meal.title like this.

148
00:08:08,000 --> 00:08:11,000
If we do that and save everything,

149
00:08:11,000 --> 00:08:14,000
I don't get anything here.

150
00:08:14,000 --> 00:08:18,000
Now the reason for that is that getMeal actually

151
00:08:18,000 --> 00:08:22,000
returns a promise because I'm using this async keyword here

152
00:08:23,000 --> 00:08:26,000
and I added that so that we could add such a delay again

153
00:08:26,000 --> 00:08:27,000
if we wanted to

154
00:08:27,000 --> 00:08:30,000
and if we wanted to set up a dedicated loading page

155
00:08:30,000 --> 00:08:31,000
or handle loading in any other way.

156
00:08:33,000 --> 00:08:34,000
Now I actually won't do that here,

157
00:08:34,000 --> 00:08:38,000
and therefore, we can simply get rid of the async keyword,

158
00:08:39,000 --> 00:08:43,000
therefore getMeal will no longer return a promise,

159
00:08:43,000 --> 00:08:45,000
and therefore, now the code should work.

160
00:08:46,000 --> 00:08:49,000
Indeed, if I now go back, I now see that title here,

161
00:08:49,000 --> 00:08:52,000
which is now fetched from the database.

162
00:08:53,000 --> 00:08:55,000
And of course that means

163
00:08:55,000 --> 00:08:58,000
that we can now also output all the other data.

164
00:08:59,000 --> 00:09:00,000
For example, on the image,

165
00:09:00,000 --> 00:09:04,000
we can set the src prop here to meal.image

166
00:09:07,000 --> 00:09:10,000
because we'll have such a image key in the database

167
00:09:10,000 --> 00:09:12,000
and we're fetching that data now.

168
00:09:13,000 --> 00:09:16,000
The alt text can be set to meal.title.

169
00:09:18,000 --> 00:09:19,000
Here for the email address,

170
00:09:19,000 --> 00:09:24,000
we can use meal.creator_email

171
00:09:25,000 --> 00:09:28,000
because that's the name I'm using in a database.

172
00:09:28,000 --> 00:09:30,000
You can see those names

173
00:09:30,000 --> 00:09:34,000
if you take a look at this initdb.js file,

174
00:09:34,000 --> 00:09:36,000
there, I have these field names

175
00:09:36,000 --> 00:09:38,000
and that's what I'm now accessing here

176
00:09:38,000 --> 00:09:40,000
in this Meal Detail page.

177
00:09:41,000 --> 00:09:46,000
And the name can therefore be output by using meal.creator.

178
00:09:48,000 --> 00:09:50,000
Now for the summary, it's meal.summary.

179
00:09:52,000 --> 00:09:57,000
And for the HTML code down there, it's meal.instructions

180
00:09:58,000 --> 00:10:00,000
without those curly braces though.

181
00:10:03,000 --> 00:10:06,000
With all that done, if you now go back and reload,

182
00:10:06,000 --> 00:10:09,000
you should see this meal page here.

183
00:10:11,000 --> 00:10:13,000
Now you'll also see that this content down there

184
00:10:13,000 --> 00:10:15,000
is not formatted perfectly.

185
00:10:15,000 --> 00:10:18,000
And the reason for that is that the line breaks we got

186
00:10:18,000 --> 00:10:20,000
in these instructions are ignored.

187
00:10:21,000 --> 00:10:25,000
We can fix this by overriding meal.instructions

188
00:10:26,000 --> 00:10:30,000
with meal.instructions.replace,

189
00:10:30,000 --> 00:10:32,000
hence replacing parts of that string.

190
00:10:33,000 --> 00:10:36,000
And here we can then use our regular expression

191
00:10:36,000 --> 00:10:39,000
to look for all line breaks which are identified

192
00:10:39,000 --> 00:10:41,000
by this special character.

193
00:10:42,000 --> 00:10:45,000
Look for all of them in this string,

194
00:10:45,000 --> 00:10:49,000
and by then replacing them with the br tag,

195
00:10:50,000 --> 00:10:52,000
the line break tag.

196
00:10:53,000 --> 00:10:56,000
If we do that, you see that the line breaks are back,

197
00:10:57,000 --> 00:10:59,000
and that's now how we can load

198
00:10:59,000 --> 00:11:02,000
and display those meal details.

