1
00:00:00,000 --> 00:00:01,000
So let's get started

2
00:00:01,000 --> 00:00:04,000
working on this website here.

3
00:00:04,000 --> 00:00:08,000
And I wanna start with creating user accounts,

4
00:00:08,000 --> 00:00:11,000
because, of course, we need user accounts first

5
00:00:11,000 --> 00:00:14,000
before we then can log users in.

6
00:00:15,000 --> 00:00:17,000
So, therefore, I wanna make sure

7
00:00:17,000 --> 00:00:20,000
that if we click this Create Account button here,

8
00:00:20,000 --> 00:00:23,000
we submit the entered data,

9
00:00:23,000 --> 00:00:25,000
and I therefor wanna make sure

10
00:00:25,000 --> 00:00:28,000
that only valid data is accepted,

11
00:00:28,000 --> 00:00:30,000
and we create a new user

12
00:00:30,000 --> 00:00:33,000
with that email-password combination.

13
00:00:34,000 --> 00:00:36,000
Now, as I mentioned in the previous lecture already,

14
00:00:36,000 --> 00:00:38,000
this starting project

15
00:00:38,000 --> 00:00:41,000
already comes with a database in the end

16
00:00:41,000 --> 00:00:43,000
that will contain a user's table,

17
00:00:43,000 --> 00:00:47,000
where we need to store a unique email and a password.

18
00:00:47,000 --> 00:00:51,000
So that's exactly what I wanna do as a first step now.

19
00:00:51,000 --> 00:00:54,000
And, therefore, on this auth form here,

20
00:00:54,000 --> 00:00:57,000
I wanna add a Server Action

21
00:00:57,000 --> 00:00:59,000
that handles the form of submission,

22
00:00:59,000 --> 00:01:02,000
where we extract the email-password combination

23
00:01:02,000 --> 00:01:04,000
and store it in the database.

24
00:01:05,000 --> 00:01:10,000
And I actually don't just wanna extract and store that data.

25
00:01:10,000 --> 00:01:14,000
Instead, I also wanna validate it so that we, for example,

26
00:01:14,000 --> 00:01:18,000
catch values that aren't valid email addresses,

27
00:01:18,000 --> 00:01:20,000
or potentially also passwords

28
00:01:20,000 --> 00:01:22,000
which are too short, let's say.

29
00:01:23,000 --> 00:01:25,000
And therefore, as a first step,

30
00:01:25,000 --> 00:01:28,000
I'll add a new folder in this project,

31
00:01:28,000 --> 00:01:29,000
in the root project folder,

32
00:01:29,000 --> 00:01:31,000
and I'll name it actions,

33
00:01:31,000 --> 00:01:34,000
because here, I wanna store my Server Actions

34
00:01:34,000 --> 00:01:36,000
in separate files.

35
00:01:36,000 --> 00:01:39,000
That's of course not something you have to do,

36
00:01:39,000 --> 00:01:40,000
as you learned in this course,

37
00:01:40,000 --> 00:01:42,000
but it is something I will do here.

38
00:01:44,000 --> 00:01:47,000
And therefore here I'll add an auth.js file,

39
00:01:47,000 --> 00:01:52,000
or maybe auth-actions.js to make it clear

40
00:01:52,000 --> 00:01:54,000
that we'll store some Server Actions in there.

41
00:01:54,000 --> 00:01:56,000
The name of course is up to you.

42
00:01:57,000 --> 00:02:02,000
And then in that file, I'll add this 'use server' directive

43
00:02:02,000 --> 00:02:03,000
at the top of this file,

44
00:02:03,000 --> 00:02:05,000
because as you learned in this course,

45
00:02:05,000 --> 00:02:09,000
if you wanna create functions that should serve

46
00:02:09,000 --> 00:02:13,000
as Server Actions in a NextJS application,

47
00:02:13,000 --> 00:02:17,000
you need to add this 'use server' directive here

48
00:02:17,000 --> 00:02:21,000
at the top of the file where you create those functions

49
00:02:21,000 --> 00:02:24,000
or inside of the functions themselves.

50
00:02:24,000 --> 00:02:27,000
And here, since I have a separate file, I add it at the top.

51
00:02:28,000 --> 00:02:30,000
Okay, so that's the first step.

52
00:02:30,000 --> 00:02:35,000
The next step is to create a new async function in here,

53
00:02:35,000 --> 00:02:37,000
and it must be async as you learned.

54
00:02:37,000 --> 00:02:41,000
Server Actions are async functions,

55
00:02:41,000 --> 00:02:43,000
which I'll name, signup.

56
00:02:43,000 --> 00:02:44,000
The name of course is up to you,

57
00:02:44,000 --> 00:02:47,000
but this name should be pretty descriptive

58
00:02:47,000 --> 00:02:51,000
regarding what this function will do.

59
00:02:51,000 --> 00:02:53,000
Well, and then this function

60
00:02:53,000 --> 00:02:56,000
will eventually receive some form data as you learned

61
00:02:56,000 --> 00:02:59,000
since I plan on using it as a Server Action

62
00:02:59,000 --> 00:03:02,000
and since I plan on assigning it to a form.

63
00:03:02,000 --> 00:03:06,000
And then NextJS will automatically provide that form data.

64
00:03:08,000 --> 00:03:12,000
And here, I'll then extract my email from that form data,

65
00:03:12,000 --> 00:03:14,000
with formData.get email,

66
00:03:14,000 --> 00:03:19,000
and my password with formData.get password, like this.

67
00:03:21,000 --> 00:03:24,000
And of course, these names, email, and password,

68
00:03:24,000 --> 00:03:27,000
are not some random names I picked here,

69
00:03:27,000 --> 00:03:29,000
but instead, these are the names you'll find

70
00:03:29,000 --> 00:03:34,000
in the auth form here, assigned to the name attribute.

71
00:03:36,000 --> 00:03:39,000
So, that will allow us to retrieve

72
00:03:39,000 --> 00:03:41,000
the email and the password.

73
00:03:41,000 --> 00:03:43,000
And with that retrieved,

74
00:03:43,000 --> 00:03:46,000
we of course eventually wanna store it in the database,

75
00:03:46,000 --> 00:03:49,000
so we want to create a new user.

76
00:03:49,000 --> 00:03:53,000
But first, I wanna validate that data.

77
00:03:53,000 --> 00:03:57,000
And there would be various ways of doing that.

78
00:03:57,000 --> 00:04:01,000
I'll validate that data by creating an errors object,

79
00:04:01,000 --> 00:04:03,000
which initially is an empty object.

80
00:04:03,000 --> 00:04:06,000
And I'll then check if my email

81
00:04:06,000 --> 00:04:11,000
does not include an @ symbol.

82
00:04:11,000 --> 00:04:14,000
So a pretty basic check, but better than nothing.

83
00:04:15,000 --> 00:04:16,000
And if that's the case,

84
00:04:16,000 --> 00:04:20,000
I wanna add a new field to that errors object,

85
00:04:20,000 --> 00:04:22,000
let's say, a field named, email,

86
00:04:22,000 --> 00:04:24,000
which contains the error message.

87
00:04:24,000 --> 00:04:26,000
And in my case here, that will be,

88
00:04:26,000 --> 00:04:29,000
"Please enter a valid email address,"

89
00:04:29,000 --> 00:04:30,000
or something like this.

90
00:04:32,000 --> 00:04:33,000
So that's the first check.

91
00:04:33,000 --> 00:04:38,000
The next check is to check if the password,

92
00:04:39,000 --> 00:04:43,000
after trimming it to remove excess wide space

93
00:04:43,000 --> 00:04:45,000
at the beginning or end,

94
00:04:45,000 --> 00:04:47,000
if it then has a length

95
00:04:47,000 --> 00:04:50,000
that's smaller than eight, let's say,

96
00:04:51,000 --> 00:04:54,000
so that we force the user to pick a password

97
00:04:54,000 --> 00:04:59,000
that's at least eight characters long for security reasons.

98
00:05:00,000 --> 00:05:02,000
So if we have a shorter password,

99
00:05:02,000 --> 00:05:06,000
I'll add a password field to the errors object.

100
00:05:06,000 --> 00:05:10,000
And in there, we could have an error message like,

101
00:05:10,000 --> 00:05:14,000
"Password must be at least 8 characters long,"

102
00:05:14,000 --> 00:05:16,000
to tell the user what's wrong.

103
00:05:18,000 --> 00:05:21,000
Though of course, just by creating this errors object,

104
00:05:21,000 --> 00:05:24,000
we won't do anything.

105
00:05:24,000 --> 00:05:29,000
Instead, we of course, need to kind of pass this object here

106
00:05:29,000 --> 00:05:34,000
to our front end to our form and output it there.

107
00:05:34,000 --> 00:05:38,000
And you did learn in this course how that can be achieved

108
00:05:39,000 --> 00:05:42,000
with help of the use form state hook.

109
00:05:43,000 --> 00:05:46,000
So, here in the auth-form.js file,

110
00:05:46,000 --> 00:05:51,000
we can actually import something from react-dom

111
00:05:52,000 --> 00:05:55,000
and that something is the use form state hook,

112
00:05:55,000 --> 00:05:58,000
about which you learned earlier in the course already.

113
00:06:00,000 --> 00:06:02,000
There, you also learned that this hook

114
00:06:02,000 --> 00:06:05,000
only works in a client component,

115
00:06:05,000 --> 00:06:09,000
and therefore I'll add the 'use client' directive here,

116
00:06:09,000 --> 00:06:12,000
at the top of the auth-form.js file.

117
00:06:13,000 --> 00:06:14,000
Well, and then with that,

118
00:06:14,000 --> 00:06:19,000
we can call use form state here in the auth form.

119
00:06:19,000 --> 00:06:23,000
And we now need to pass the Server Action

120
00:06:23,000 --> 00:06:27,000
that should be handled with help of the use form state hook

121
00:06:27,000 --> 00:06:30,000
as a first argument to that hook.

122
00:06:30,000 --> 00:06:33,000
And that Server Action, of course,

123
00:06:33,000 --> 00:06:36,000
is that signup action I'm working on here.

124
00:06:37,000 --> 00:06:40,000
Therefore, we should actually export this function

125
00:06:40,000 --> 00:06:42,000
from the auth actions file,

126
00:06:44,000 --> 00:06:47,000
so that in auth-form.js we can import it,

127
00:06:47,000 --> 00:06:51,000
and import this signup function from the actions folder

128
00:06:51,000 --> 00:06:54,000
and the auth actions file.

129
00:06:54,000 --> 00:06:57,000
And it's then this signup action that will be passed

130
00:06:57,000 --> 00:07:00,000
as a first argument to use form state.

131
00:07:01,000 --> 00:07:05,000
The second argument as you learned is the initial state,

132
00:07:05,000 --> 00:07:08,000
and in my case here, that will be an empty object.

133
00:07:08,000 --> 00:07:12,000
And then we'll get back an array with exactly two elements,

134
00:07:12,000 --> 00:07:15,000
where the first element will be the form state,

135
00:07:15,000 --> 00:07:18,000
and the second argument will be the action.

136
00:07:18,000 --> 00:07:20,000
So, this signup action

137
00:07:20,000 --> 00:07:25,000
but actually wrapped with an extra function essentially

138
00:07:25,000 --> 00:07:28,000
that allows React to listen to that action

139
00:07:28,000 --> 00:07:30,000
and manage this form state for us.

140
00:07:31,000 --> 00:07:33,000
So it's then this form action

141
00:07:33,000 --> 00:07:36,000
that should be assigned to the form as an action

142
00:07:36,000 --> 00:07:39,000
through the action prop, like this.

143
00:07:41,000 --> 00:07:42,000
And it's then the form state

144
00:07:42,000 --> 00:07:47,000
that can be used to output the potential error messages

145
00:07:47,000 --> 00:07:49,000
we might be getting due to incorrect values.

146
00:07:51,000 --> 00:07:55,000
And here in this form, I wanna output those errors

147
00:07:55,000 --> 00:07:57,000
above my submit button here.

148
00:07:59,000 --> 00:08:04,000
And here, I'll check if my form state has an errors key.

149
00:08:05,000 --> 00:08:09,000
Initially, it's an empty object with no keys,

150
00:08:09,000 --> 00:08:12,000
but I plan on adding an errors key here

151
00:08:12,000 --> 00:08:13,000
in the signup function soon.

152
00:08:13,000 --> 00:08:17,000
It's not there yet, but it will soon be there.

153
00:08:17,000 --> 00:08:21,000
Therefore, this form state should actually be

154
00:08:21,000 --> 00:08:23,000
an object with an error key

155
00:08:23,000 --> 00:08:26,000
if we have some validation errors.

156
00:08:26,000 --> 00:08:28,000
And therefore, here, I'll check if that's truthy.

157
00:08:28,000 --> 00:08:32,000
So if we have an error key with some values.

158
00:08:33,000 --> 00:08:34,000
And if that's the case,

159
00:08:34,000 --> 00:08:37,000
I wanna output an unordered list

160
00:08:37,000 --> 00:08:40,000
with an ID of form-errors,

161
00:08:40,000 --> 00:08:43,000
and that's an ID you should add for styling purposes.

162
00:08:44,000 --> 00:08:47,000
And in that list, I'll then output

163
00:08:47,000 --> 00:08:50,000
those various errors messages we might have.

164
00:08:51,000 --> 00:08:54,000
And I expect errors to be an object

165
00:08:54,000 --> 00:08:57,000
that will have this shape.

166
00:08:57,000 --> 00:09:01,000
So, an object that has an email or a password key,

167
00:09:01,000 --> 00:09:04,000
or both, depending on what's invalid.

168
00:09:05,000 --> 00:09:07,000
And we can therefore map those keys

169
00:09:07,000 --> 00:09:10,000
in that errors object to list items

170
00:09:10,000 --> 00:09:12,000
by using Object.keys,

171
00:09:12,000 --> 00:09:15,000
which is a method built into JavaScript,

172
00:09:15,000 --> 00:09:18,000
which in the end converts a list of keys into an array.

173
00:09:19,000 --> 00:09:23,000
We pass the form state errors object to it,

174
00:09:23,000 --> 00:09:27,000
and that will then give us an array of those keys,

175
00:09:27,000 --> 00:09:29,000
so of those key value pairs

176
00:09:29,000 --> 00:09:32,000
that are stored in that errors object.

177
00:09:32,000 --> 00:09:34,000
And here, I can then go

178
00:09:34,000 --> 00:09:38,000
through those different key value pair objects.

179
00:09:38,000 --> 00:09:40,000
And for every key value pair object,

180
00:09:40,000 --> 00:09:42,000
I'll render a list item

181
00:09:42,000 --> 00:09:46,000
where the key should be the key name here.

182
00:09:46,000 --> 00:09:49,000
So that will in the end just be the key name

183
00:09:49,000 --> 00:09:52,000
of the different keys we're going through here

184
00:09:52,000 --> 00:09:53,000
for this errors object.

185
00:09:54,000 --> 00:09:58,000
And the value I then wanna output here for that list item,

186
00:09:58,000 --> 00:10:01,000
well, that will be formState.errors.

187
00:10:01,000 --> 00:10:04,000
And then I access the value for this specific key

188
00:10:04,000 --> 00:10:06,000
we're currently looking at.

189
00:10:08,000 --> 00:10:13,000
So the key here, error, will be email or password,

190
00:10:13,000 --> 00:10:16,000
since these will be the only keys I add to this object,

191
00:10:16,000 --> 00:10:19,000
and the values will then be the error messages.

192
00:10:20,000 --> 00:10:24,000
And it's these errors which output here.

193
00:10:24,000 --> 00:10:26,000
So that should then output

194
00:10:26,000 --> 00:10:29,000
any validation form errors we might have,

195
00:10:29,000 --> 00:10:31,000
but we're not done yet.

196
00:10:32,000 --> 00:10:34,000
This is an important first step,

197
00:10:34,000 --> 00:10:36,000
but as you learned,

198
00:10:36,000 --> 00:10:40,000
if you wrap an action with use form state,

199
00:10:40,000 --> 00:10:44,000
you need to tweak that Server Action function a little bit,

200
00:10:44,000 --> 00:10:48,000
because it will now no longer directly get the form data,

201
00:10:48,000 --> 00:10:51,000
or it will not just get the form data.

202
00:10:51,000 --> 00:10:54,000
Instead, it will now actually get two arguments,

203
00:10:54,000 --> 00:10:55,000
two parameters

204
00:10:55,000 --> 00:10:59,000
where the second parameter will be the form data,

205
00:10:59,000 --> 00:11:02,000
and the first parameter will be the previous form state.

206
00:11:03,000 --> 00:11:05,000
Now, I don't need that here,

207
00:11:05,000 --> 00:11:07,000
but we still need to accept it

208
00:11:07,000 --> 00:11:11,000
to make sure that we correctly extract that form data.

209
00:11:12,000 --> 00:11:15,000
It must be the second parameter here.

210
00:11:16,000 --> 00:11:20,000
And, of course, I now also must return this errors object

211
00:11:20,000 --> 00:11:23,000
stored under a key named, errors,

212
00:11:23,000 --> 00:11:26,000
so that this code does its job.

213
00:11:27,000 --> 00:11:31,000
Hence, in the auth-actions.js file,

214
00:11:31,000 --> 00:11:34,000
I wanna check, after running these checks here,

215
00:11:34,000 --> 00:11:36,000
if I got any errors

216
00:11:36,000 --> 00:11:39,000
because we don't necessarily have any.

217
00:11:39,000 --> 00:11:43,000
After all, we could make it pass both if checks here

218
00:11:43,000 --> 00:11:45,000
without having any error,

219
00:11:45,000 --> 00:11:47,000
if the user did enter valid values.

220
00:11:47,000 --> 00:11:50,000
But we will know that we have at least one error

221
00:11:50,000 --> 00:11:55,000
if we have the email or password key in that object.

222
00:11:55,000 --> 00:11:57,000
Or to put it in another way,

223
00:11:57,000 --> 00:12:01,000
if we have any keys at all in that errors object.

224
00:12:02,000 --> 00:12:05,000
So I'll add a third "if" check here,

225
00:12:05,000 --> 00:12:10,000
and check if the keys in that errors object...

226
00:12:12,000 --> 00:12:14,000
Keep in mind this converts

227
00:12:14,000 --> 00:12:17,000
the key value pairs of that object to an array

228
00:12:17,000 --> 00:12:21,000
if that array has a length that's greater than zero,

229
00:12:21,000 --> 00:12:23,000
which means we have at least

230
00:12:23,000 --> 00:12:27,000
one key value pair in that object,

231
00:12:27,000 --> 00:12:28,000
which will only be the case

232
00:12:28,000 --> 00:12:31,000
if at least one of those checks failed.

233
00:12:31,000 --> 00:12:35,000
So if we made it into at least one of those "if" statements.

234
00:12:37,000 --> 00:12:40,000
So if we have at least one key in the errors object,

235
00:12:40,000 --> 00:12:44,000
I know that at least one invalid value has been entered.

236
00:12:44,000 --> 00:12:47,000
And in that case, I wanna send back a new object

237
00:12:47,000 --> 00:12:49,000
as a response.

238
00:12:49,000 --> 00:12:52,000
As you learned, whatever you return in a Server Action

239
00:12:52,000 --> 00:12:56,000
will be sent back as a response to the client,

240
00:12:56,000 --> 00:13:00,000
and this object will then become the new form state.

241
00:13:00,000 --> 00:13:02,000
So the new value exposed

242
00:13:02,000 --> 00:13:07,000
through that form state variable here in our auth form,

243
00:13:08,000 --> 00:13:11,000
that should be an object with a key of errors

244
00:13:11,000 --> 00:13:14,000
to show those errors.

245
00:13:14,000 --> 00:13:17,000
So, therefore, I'll add a key named, errors, to this object,

246
00:13:17,000 --> 00:13:19,000
and the value stored under that key

247
00:13:19,000 --> 00:13:22,000
should be this errors object.

248
00:13:22,000 --> 00:13:24,000
So it has the same name.

249
00:13:24,000 --> 00:13:25,000
And if the key name

250
00:13:25,000 --> 00:13:29,000
and the variable or a constant name that holds the value

251
00:13:29,000 --> 00:13:32,000
that should be stored under the key are the same,

252
00:13:32,000 --> 00:13:34,000
you can actually shorten that in JavaScript

253
00:13:34,000 --> 00:13:36,000
and write it like this.

254
00:13:37,000 --> 00:13:40,000
And that's now the validation code I wanna add.

255
00:13:40,000 --> 00:13:43,000
The validation code in the Server Action

256
00:13:43,000 --> 00:13:45,000
and the code in the auth form

257
00:13:45,000 --> 00:13:48,000
to show those validation errors.

258
00:13:49,000 --> 00:13:51,000
With that, if you save this,

259
00:13:51,000 --> 00:13:55,000
if you save all files and you reload this page,

260
00:13:55,000 --> 00:13:57,000
for example, enter a valid email address.

261
00:13:57,000 --> 00:13:59,000
But if the password is too short

262
00:13:59,000 --> 00:14:01,000
and you click Create Account,

263
00:14:01,000 --> 00:14:03,000
you should see this error message.

264
00:14:05,000 --> 00:14:07,000
Now, if you enter a valid value,

265
00:14:07,000 --> 00:14:09,000
so a valid email and a valid password,

266
00:14:09,000 --> 00:14:11,000
you'll actually get an error

267
00:14:11,000 --> 00:14:14,000
because we're not handling that case yet.

268
00:14:14,000 --> 00:14:19,000
That scenario, that's the user entered a valid value.

269
00:14:19,000 --> 00:14:21,000
But that's what we'll do next.

270
00:14:21,000 --> 00:14:24,000
Because it's of course in that scenario,

271
00:14:24,000 --> 00:14:26,000
that valid values we're entered,

272
00:14:26,000 --> 00:14:29,000
that we wanna create a new user,

273
00:14:29,000 --> 00:14:31,000
store it in the database,

274
00:14:31,000 --> 00:14:33,000
and do a bunch of other things.

