
No Comments Yet
Be the first to share your thoughts and start the conversation.
Be the first to share your thoughts and start the conversation.
How did you manage to remove the blur property and reach here?
Upgrading gives you access to quizzes so you can test your knowledge, track progress, and improve your skills.
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
In this lesson, we explore the implementation of one-time password (OTP) verification specifically designed for hospital admin logins. The process involves creating a secure method for admins to access the admin interface through a passkey modal that verifies their identity. Detailed steps illustrate the coding required to set up this verification feature effectively.
00:00:00 And this starts with creating the OTP verification for admins to log in.
00:00:05 A hospital will create a special pin that they'll be able to type in and log into the admin interface.
00:00:11 So let's implement that next.
00:00:14 Back in the code, I will close all of the currently open files.
00:00:18 And I will navigate over back to the first page that we worked on, which is the homepage.
00:00:24 And if we remember here, we said that sometime we might want to show this passkey model.
00:00:30 So how will that work?
00:00:33 Well, let me show you.
00:00:34 Whenever we click admin right here, it'll add admin is true to the search params.
00:00:40 So we can extract that.
00:00:42 And now you know how.
00:00:43 You can just destructure the search params and that'll be of a type search param props.
00:00:50 And right here, we can check if a user wants to log in as admin.
00:00:54 So const is admin is equal to searchparams.admin.
00:00:59 And if that is set to true, then we know that we want to show a passkey modal.
00:01:05 So let's create a new component.
00:01:15 And here we can remove this to do, and instead of it, we can say, if isAdmin, then we want to render a.
00:01:23 passkey modal component coming from components, passkey modal.
00:01:28 So now if we do that and go back to the code, you can see at the top passkey modal.
00:01:34 I can just go back to localhost 3000. Nothing is there.
00:01:38 But if I click admin, it opens up this passkey modal.
00:01:41 But we want to show it on top of the screen and not just at the top left.
00:01:46 Just to remind you, this is what we want to do.
00:01:49 So let's go back to the code and let's implement this OTP verification model next.
00:01:55 To start working on the passkey model, we'll have to divide it into two different parts, the model and the passkey.
00:02:03 So let's start focusing from the outside to the inside and creating the model first.
00:02:09 Of course, for that, we'll use ShadZN.
00:02:12 Specifically, we'll use a ShadZN alert dialog.
00:02:16 So let's Google it.
00:02:18 And we'll see here, once you click it, it will open up this nice looking dialog.
00:02:24 So we want to just install it by running MPX, ShadZee and UI latest add dialog.
00:02:30 So let's go here and install it.
00:02:34 And let's see how we can use it.
00:02:36 Well, we can use it by importing all of these things right here, right at the top, and then using it.
00:02:43 So let's copy this part as well and use it right here.
00:02:49 by overriding everything we have in the passkey model.
00:02:54 Let's also indent it properly.
00:02:56 Let's save it.
00:02:57 And let's go back to the application.
00:03:00 And if you click open, now the model opens.
00:03:04 But of course, we'll have to style it further.
00:03:06 So let's do just that.
00:03:08 We also have to know when it is opened or closed.
00:03:11 So for that reason, I'll create a new useState snippet, call it open, set open at the start set to false.
00:03:20 And of course we have to import useState from React And since we're using hooks, we also have to make it a useClient component.
00:03:30 Great.
00:03:32 Also, it's going to be a lowercase open.
00:03:35 And now we can pass this state to the alert dialog by saying open is equal to open and onOpenChange is equal to setOpen because that's the setter function
00:03:51 to change it.
00:03:52 Now, when it comes to this trigger, we don't necessarily need to have it here because we'll trigger the opening of a dialog somewhere else.
00:04:00 So we can remove this trigger and we can focus just on the dialog content.
00:04:05 The dialog content will have a class name equal to shad-alert-dialog.
00:04:13 Then we'll have a header and we'll have a title.
00:04:16 The title will have a class name equal to flex-items-start and justify-between.
00:04:25 And in there, we can say something along the lines of, let's do admin access verification.
00:04:36 And if we save it and go back, oh, it's gone.
00:04:40 And if I click admin, nothing happens.
00:04:43 So for now, let's keep the open state to true by default.
00:04:47 There we go.
00:04:48 Now we can see it.
00:04:49 Admin access verification.
00:04:51 Let's focus on the other aspects of the model by going still within the title, rendering an image.
00:05:00 And this image will come from next image and it'll have a source equal to forward slash assets, forward slash icons, forward slash close dot SVG with an
00:05:13 alt tag of close, a width of about 20, a height of about 20. And on click, what it can do is it can call the closeModel function.
00:05:26 That's going to look something like this.
00:05:28 And of course, we are yet to define this function.
00:05:31 So let's do just that by saying const closeModel will simply set the open to false.
00:05:38 And we also want to remove that isAdmin is true from the URL.
00:05:43 So for that reason, we'll need to get access to the router by saying const router is equal to use router coming from next navigation.
00:05:53 And we can also just say router.push.
00:05:57 And we want to push just to the forward slash without the admin open.
00:06:01 Okay, that's great.
00:06:02 And also, we can give it a class name equal to cursor-pointer so we know that it is clickable.
00:06:10 Great.
00:06:11 It closes and we click it, it opens.
00:06:14 Great.
00:06:15 Now, let's go below the title and let's modify the description and say, to access the admin page, please enter the pass key.
00:06:27 Okay.
00:06:28 And now we can go below the alert dialog header, and we can create a new div.
00:06:33 This div will now render that pass key.
00:06:36 And for that, we'll also be using ChatCN.
00:06:39 So if you go to ChatCN, you can search for input OTP.
00:06:43 And who would have said that they also implemented this component?
00:06:46 That's pretty cool.
00:06:47 Let's just install it.
00:06:49 We're going to go here and just add Schatzian UI latest, add input OTP.
00:06:55 And I think I have already added these to the Tailwind config, so we should be good.
00:07:00 We just need to import its usage.
00:07:03 We can do that right at the top below the alert dialog.
00:07:10 And we need to use it.
00:07:12 So let's copy its usage.
00:07:15 And we'll use it within this div.
00:07:18 Let's properly indent it and let's modify it a bit.
00:07:23 Max length six.
00:07:24 And we also need to give it an on change so we know what our user is typing.
00:07:29 And for that reason, we can create a new use state at the top.
00:07:33 So that's going to be a use state snippet.
00:07:36 We'll call it pass key, set pass key at the start set to an empty string.
00:07:43 And if we go down to this input OTP, we can pass a value equal to passKey and then onChange, which is a callback function that accepts a value.
00:07:57 And then it simply sets the passKey to be that value.
00:08:02 We can also style it a bit by styling this OTP group with a class name of shad-otp.
00:08:10 We don't need a separator or another group.
00:08:13 Rather, we'll keep all of these slots in one group.
00:08:16 And we need to give all of them a single class name, which will be equal to shad-otp-slot.
00:08:25 And they're going to have different indices.
00:08:27 So let's save it.
00:08:28 Go back.
00:08:31 and we have this beautiful looking OTP form.
00:08:35 Great.
00:08:36 And we can type into it, we can delete values.
00:08:39 It just works so great.
00:08:41 Also, if there is an error with the pass key, we need to be able to show it.
00:08:45 So let's go up and create a new use state field.
00:08:50 I'll call it error and set error at the start equal to an empty string because that's actually gonna be an error message.
00:08:58 And we need to properly spell the error here.
00:09:01 That's good.
00:09:02 And just below the input OTP, if there is an error, then we want to display a p tag with a class name equal to shad-error,
00:09:14 text-14-regular, and margin top of four.
00:09:21 We can also give it a flex and justify-center.
00:09:25 Right within it, we can render the error message.
00:09:29 Great.
00:09:30 As simple as that.
00:09:32 Now, finally, we have the alert dialog footer, and we don't need a cancel, but we need an action within which we can just say,
00:09:40 enter admin passkey.
00:09:44 This is going to be to submit it, and we can give it an on click.
00:09:49 That accepts the click event.
00:09:52 And we'll call a function called validate passkey and we'll pass that event.
00:09:57 And we'll also give it a class name equal to shat-primary-btn and w-full.
00:10:06 But of course, before we check it out in the browser, we have to create this validate passkey function.
00:10:11 So let's do that at the top.
00:10:13 const validate passkey is a function that accepts an event.
00:10:17 Great.
00:10:18 Let's go back to the code.
00:10:20 and let's try it out enter passkey and it seems like it works but for now we're not really doing any verification right we're not testing it so now that
00:10:31 we have the ui we can go back and we can implement this validate passkey function so let's first define the type for our event that's going to be a react
00:10:42 dot mouse event and specifically an HTML button element click and mouse event like this.
00:10:50 And first, we want to run the E.preventDefault to prevent the default behavior of the browser on submit clicks, which is to reload.
00:10:59 And here, we want to check if passkey is triple equal to process.env.next-public-admin-passkey And if that is the case, that means that we have successfully
00:11:15 entered the admin dashboard.
00:11:16 Else, we can simply set the error and set invalid pass key.
00:11:22 Please try again.
00:11:24 Okay, so let's give it a shot.
00:11:27 Let's go back and type something invalid.
00:11:30 And you can see invalid passkey, please try again.
00:11:33 That's good.
00:11:34 And as you can notice from here, for the time being, we'll be storing the passkey in the environment variables.
00:11:40 Later on, if you want to extend this application, your healthcare admin provider will be providing their passkey and you'll have to verify it and check
00:11:48 whether it matches.
00:11:49 But for now, we'll put it right here.
00:11:51 That's going to be next, underscore public, underscore admin passkey, and I'll set it to 123456. Great.
00:11:58 So now if we go back, we can figure out what happens if we enter the correct pass key.
00:12:09 So first of all, we can get an encrypted key, which will mean that we're properly logged in.
00:12:14 So encrypted key is equal to encrypt key coming from libutils to which we pass this pass key.
00:12:24 And we want to set it to the local storage by calling localStorage.setItem accessKey is equal to encryptedKey.
00:12:34 And once again, you are basically exchanging the passkey, which is just a set of six digits, for an encrypted key so that whatever you do within the platform,
00:12:44 they know who did it.
00:12:46 Not by name, but rather by the encrypted key.
00:12:49 And this function right now is just a basic encryption key where we just pass a key and then it gives us an encrypted version of it.
00:12:57 Nothing special happening here, but it gives you the possibility to extend it further.
00:13:02 Finally, we can set open to false because we're done with the encryption.
00:13:07 And there's one more thing we want to do.
00:13:09 We don't want to let the admin try to sign in again in case they already have their exchanged access key saved into the local storage.
00:13:17 So first, let's try to get it from the local storage by saying const encrypted key is equal to If type of window is not equal to undefined,
00:13:30 this means that we are actually in the browser and we can try to fetch it.
00:13:34 Then we can try to get the window dot local storage dot get item.
00:13:40 And we can try to access the access key.
00:13:43 Else it'll be set to null.
00:13:44 Okay.
00:13:46 So now we have the access key, and now we can create a useEffect snippet, which will allow us to check whether the access key exists.
00:13:55 And then we can decrypt it to get the actual pass key.
00:13:59 So let's first fix this.
00:14:01 Let's import useEffect from React, and let's recall it whenever we fetch the encrypted key, okay?
00:14:08 That's coming from here.
00:14:10 So what will we try to do once we have it?
00:14:12 Well, we have to check the path of our browser.
00:14:15 If we're on the path where the path key needs to be entered, then we can try to log in.
00:14:21 So const path is equal to use path name coming from next navigation.
00:14:26 And then we can say, if path exists, that means that we're in the client side.
00:14:31 We can try to log in by doing the same thing that we're doing right here.
00:14:35 So we can basically copy this part right here.
00:14:40 If passkey is equal to the one in local storage, then we don't have to set it to local storage anymore.
00:14:46 We can just set open to false and we can run the router.push and push to the forward slash admin page.
00:14:53 Otherwise we can set open to true because it wasn't successfully fetched.
00:14:59 I think this will be good for now.
00:15:01 So let's give it a shot.
00:15:04 If I go back and just reload the page on localhost 3000 and click Admin, it opens up, we close it, it closes.
00:15:12 That's good.
00:15:13 Now, if we enter something invalid, like 123.1.3 and click Enter Admin Passkey, we got invalid.
00:15:20 That's totally okay.
00:15:21 But what happens if I enter my correct one that I added to my ENVs?
00:15:25 123456 and click enter admin passkey, we get redirected to the admin dashboard.
00:15:35 But not only that, if I go to inspect and check out my local storage, if I go under application, localhost 3000, and we have this access key,
00:15:45 you can see that we now have this encrypted access key.
00:15:49 Which should mean that if I go back and open up the admin and try it once again.
00:15:54 Oh, it doesn't do it.
00:15:57 We might need to make some modifications here to this use effect.
00:16:00 Oh, we're comparing the pass key here instead of comparing the access key.
00:16:05 That's because in the use effect, we have to decrypt the key again.
00:16:08 So we can say const access key is equal to encrypted key if it exists.
00:16:17 Then we want to run decrypt key and we want to pass the encrypted key.
00:16:23 Okay.
00:16:24 And then we want to check the access key against the admin pass key.
00:16:28 Let's give that a shot.
00:16:30 So if I reload right here.
00:16:32 You can see that we automatically get redirected because it's already stored in local storage.
00:16:37 So as soon as they click admin, that's it.
00:16:40 It automatically redirects me there because it knows I'm an admin and I don't have to enter the passkey for some period of time.
00:16:48 Great.