
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 delve into the process of creating a dynamic registration page for patients using Next.js. The discussion covers setting up routes, building forms with various input types, implementing validation, and handling data submission to a backend with AppWrite. This detailed walkthrough provides insights into managing user data while ensuring a seamless user experience during registration.
00:00:00 Going back to the code base, we can now collapse this create user, the first user action we've created, and we can actually go back to the patient form
00:00:10 because believe it or not, it's done its job, right?
00:00:12 It added the user and that's all that it needed to do.
00:00:15 Next, it redirected us to patients register.
00:00:18 So that means that we can create that next page.
00:00:21 I'll go to app and create a new folder called patients.
00:00:26 Next, pay attention, each patient has its own ID.
00:00:30 So we have to create a dynamic route for each user ID.
00:00:33 So that'll be square bracket user ID, and then you close it.
00:00:38 And then within it, we can create a new folder called register.
00:00:43 And within that register, we can create a new file called page.tsx and run RAFCE.
00:00:51 This is the user registration page.
00:00:55 Let's call it like that, registration, or we can simply call it register, which is the name of the page.
00:01:02 And we can get started with implementing it.
00:01:05 And as soon as this is done, you can see that now it's no longer a 404. We can see register at the top left.
00:01:11 So let's go ahead and code it out.
00:01:13 We can give it a class name equal to flex h-screen and max-h-screen.
00:01:22 We can also wrap it with a section and that section will have a class name equal to remove-scrollbar and the container.
00:01:33 within which we'll have a div that will have a class name equal to sub-container, max-w-860px, flex-1, flex-col, and padding y of 10. And within it,
00:01:52 we can render an image.
00:01:54 Of course, this is a next image and it'll have a source equal to forward slash assets, forward slash icons, forward slash logo.svg with a height of around
00:02:08 a thousand, a width of around a thousand as well, an alt tag of care pools and a class name equal to margin bottom of 12. H of 10 and a W of fit.
00:02:24 If we save it and go back, we should be able to see a Care Pulse logo, but I think it should be logo-full.
00:02:32 And there we have it.
00:02:34 Looking good.
00:02:35 Now, this page shares some similarities to the original page that we had.
00:02:41 Of course, I'm talking about the homepage here, right?
00:02:44 We have the section, the div, the image, then the patient form, and then all the other stuff right here at the bottom.
00:02:51 So actually what we can do is we can just copy this entire homepage.
00:02:59 Bear with me.
00:03:00 Copy this entire homepage all the way until the bottom and replicate what we have done so far within the registration page.
00:03:09 Because all of it is almost exactly the same.
00:03:13 I'll explain how.
00:03:15 But comment out the patient form and make sure to import the link from next link.
00:03:23 And then instead of onboarding image, change it to register-img.
00:03:29 And instead of giving it a 50% width, let's give it a 390 pixels width.
00:03:35 So this is just a bit less than before and save it.
00:03:39 And if you go back.
00:03:40 you'll see a similar page that we had before with a new image on the right, but our thing on the left is completely blank.
00:03:48 So what we have to do is instead of rendering the patient form, instead we need to render a register form.
00:03:56 So let's create a new form in the forms folder and call it registerform.tsx.
00:04:05 For now, we can basically just copy the entire patient form and paste it into the register form because we'll just expand on what we have there and just
00:04:15 call it here register form, just like so.
00:04:19 And it won't allow us to automatically import it.
00:04:22 That's because we have to change the name right here.
00:04:24 Register form at the bottom.
00:04:27 as well as register form right here at the top.
00:04:31 So now if we go back and import it and go back, you can see it nicely right here.
00:04:36 It seems like homepage, but this is actually register because we'll completely change the inputs that we show right here.
00:04:44 But there's one difference here.
00:04:45 Now we already have the information about the user that is being registered.
00:04:50 The user is already authenticated, but we need to register them.
00:04:54 So for that reason, we can create a new patient action, export const, get user.
00:05:03 And it'll be equal to an async function where we take in a user ID of a type string and open up a try and catch block.
00:05:13 In the catch, we console that error, the actual error, and in the try, we simply get a user by saying const user is equal to await users.get,
00:05:26 and we pass the user ID to it, and then return parse stringify the user.
00:05:32 So now if we go back, we can just say const user.
00:05:37 is equal to await, of course, make sure to make this component async before, and say get user coming from lib actions, patient actions.
00:05:48 To it, we need to pass the user ID.
00:05:51 And how do we get the user ID?
00:05:53 Well, we get it from params because it is stored right here in this dynamic URL property.
00:05:59 So we can destructure the params and then destructure the user ID from it.
00:06:06 And we can give this a type of search program props.
00:06:11 Great.
00:06:12 Now on this page, we won't have any OTP verification, so we can remove this.
00:06:17 And now that we have the user, we can pass it over by saying user is equal to user to the register form.
00:06:25 We can move over to it and we can accept that prop.
00:06:28 So we can say user.
00:06:31 is of a type user, user like this.
00:06:35 And we can clean this form up a bit because we won't be needing any form field types that was used before.
00:06:42 So instead we can simply import them from where we used them before in the patient form.
00:06:47 And also we can just keep a single input just for reference, but we'll be adding a completely new set of inputs all across this component.
00:06:56 So for now, let's just keep one.
00:06:59 Okay, this is where we're at right now, and this is what we had before, but this is what we want to achieve.
00:07:09 I mean, take a look at this beefy form.
00:07:11 There is two columns of actual inputs, and there's many different categories of data, such as the personal info, medical info,
00:07:21 identification, verification, even with personal identification image uploads, and even some checkboxes.
00:07:29 for consenting to different privacy terms.
00:07:32 So this is a proper, proper form.
00:07:35 So let's turn this into this.
00:07:38 By putting our code and the browser side by side, just so we can more easily ensure that we cover all of the fields that we can see here in the design.
00:07:47 So we'll keep comparing this to the final version to make sure that we didn't miss any fields.
00:07:53 Let's start with the space above the form first.
00:07:55 Instead of space Y6, we can give it a bit more space of 12 right here.
00:08:00 And then with the section between, we can also give it a space Y of 4. Inside of it, instead of saying hi there, we can now say welcome as they are authorized.
00:08:12 And we can say, let us know.
00:08:15 More about yourself.
00:08:18 Something like that should be good.
00:08:20 We can also create another section by duplicating this one.
00:08:23 And this one will only have a P tag.
00:08:27 It'll be space Y6 and it can say something like personal information.
00:08:35 And this will be an H2 that will have a class name equal to sub dash header.
00:08:44 So let's properly close it and let's also put it within an additional div just for positioning reasons that will have a class name equal to margin bottom
00:08:55 of nine and space dash Y of one.
00:08:58 And now we can put this H two right within it.
00:09:02 So if we save this and go to our current application, you'll see something that looks like this.
00:09:10 Oh, only after we fix the error, of course.
00:09:14 There we go, one reload did it.
00:09:16 So now we have welcome and then we have personal information.
00:09:20 Now we can start creating all of those fields.
00:09:23 First, we'll have a name.
00:09:25 So basically this can remain as it is.
00:09:28 We just don't need the label in this case.
00:09:30 Next, we'll have email and phone.
00:09:33 So these are the same pieces of information to be collected on the homepage, but we can also include them here just to have a complete form.
00:09:41 So I'm going to go to the patient form and I'll just take those two inputs that I deleted before.
00:09:48 There we go.
00:09:49 copy them, and instead of pasting them immediately, I'll put them within a div.
00:09:54 So this div will have a class name equal to flex, flex-call, gap of six, and extra large devices, it'll be flex-row.
00:10:05 So they will appear one next to another.
00:10:08 And here I can paste those two custom form fields, both of type input, first one email, and second one phone number.
00:10:18 That's going to look something like this.
00:10:20 Let's compare it with the design, and you'll see that this is how it's supposed to look like on desktop.
00:10:25 So if I zoom this out a bit, we can see, well, we maybe could see what's happening on desktop, but now this image is taking way too large portion of the screen.
00:10:35 Let's see if I made a mistake here when rendering that image.
00:10:39 Oh yeah, definitely.
00:10:40 I have an extra square bracket at the end.
00:10:43 If I save it, now you can see that this makes much more sense.
00:10:47 Cool.
00:10:48 So if I zoom it out still, you can see that maybe you can see that the email and the phone number appear on left and right side right here.
00:10:57 So I will put this code a bit more to the left.
00:11:00 So we have more space for this so we can see how the form should look like on desktop.
00:11:06 And I will actually zoom it in just a bit more.
00:11:09 Perfect.
00:11:10 Let's also add a label here that I removed.
00:11:13 Now I can notice that we might need it.
00:11:14 There we go.
00:11:16 So this is good.
00:11:17 And now I'll keep this side by side so we can keep comparing the two.
00:11:21 We have the design and then we have the actual code.
00:11:25 Keep in mind, I'm zoomed out a lot, so it actually mimics the desktop mode.
00:11:32 But if you zoom it in, of course, all of the fields will show one below another.
00:11:37 Perfect.
00:11:37 Now let's see what other fields do we need.
00:11:39 I think there's a mistake in the design here.
00:11:43 This should be date of birth.
00:11:44 And then we have the gender.
00:11:46 So let's add those next by scrolling down.
00:11:50 We'll put them in another div.
00:11:53 So div with a class name equal to flex, flex-col, a gap of 6, and on extra large devices flex of row.
00:12:07 Same as before.
00:12:08 As a matter of fact, we'll have this div many, many times in the future as well, because most of these will appear in a series of two,
00:12:17 right?
00:12:18 Because we have a two column grid.
00:12:21 So I can actually duplicate this div a few more times below, as we'll have many more inputs together like that.
00:12:28 Okay, cool.
00:12:29 Now let's put something within this div.
00:12:32 As I said, it's going to be a custom form field.
00:12:35 So we might as well duplicate these two custom form fields and just change the properties.
00:12:41 That's the beauty of creating custom form fields that are reusable components.
00:12:46 But this one will be of a type date underscore picker.
00:12:50 The name will be birth date.
00:12:54 And the label will be date of birth.
00:12:57 So let's do it like that.
00:12:58 Date of birth.
00:13:01 Perfect.
00:13:02 Of course, if we save it now, it won't appear here because we haven't yet created a date picker component.
00:13:09 And then the one after that will be of a type skeleton.
00:13:13 So let's create a skeleton type right here.
00:13:16 It'll have a name of gender.
00:13:21 That'll basically be a select component.
00:13:23 And we'll also have a label of gender.
00:13:27 The reason why we're calling it a skeleton is because we can pass a custom render skeleton property that gets access to the field.
00:13:35 And then you can render whatever you want right here.
00:13:39 So we'll immediately render a form control, which we have to import from UI form right here and save it.
00:13:48 So now you can see the gender on the right side as well.
00:13:51 Within that form control, we'll render a radio group.
00:13:55 And this radio group is something we have to install.
00:13:58 So let's do that right away.
00:13:59 I'm going to go here, run mpx chat cnuilatest add radio-group.
00:14:08 Installing radio group.
00:14:10 That's good.
00:14:11 And we can also install a select component.
00:14:15 because we'll be using it later on installing select.
00:14:19 That's good.
00:14:20 And now we can import radio group from UI radio group.
00:14:24 Let's also give it a class name equal to flex H11 gap of six and an extra large devices justify dash between.
00:14:36 To this radio group, we need to pass an onValueChange equal to field.onChange.
00:14:43 And we also need to pass the default value equal to field.value.
00:14:51 And finally, within here, we can choose from all of the different gender options.
00:14:55 So here we could create an array and then list many different labels and different options like male, female, other, and all the other genders.
00:15:04 Or we can save that nicely within constants and then called it from here.
00:15:10 So if we go to constants, that's going to be a new folder right here called constants.
00:15:16 And within it, we create a new index.ts.
00:15:22 we can export const gender options, and we can say something like male, female, and we can do other as well.
00:15:36 Of course, you can see copilot automatically said, prefer not to say as well as an option.
00:15:41 You can add it if you want to.
00:15:43 And now we can just import gender options from constants and map over them by saying that map And for each option, we can automatically return a div with
00:15:59 a key equal to option and a class name equal to radio-group.
00:16:06 Within it, we can render a radio group item imported from dot dot slash UI radio group.
00:16:13 And each radio group item will have a value equal to option and also an ID equal to option.
00:16:21 And we need to render a label.
00:16:23 So this label will be coming from UI label and it will render the option.
00:16:29 We can also give it an HTML4 option to connect it to that option and give it a class name equal to cursor-pointer so people can know that they can click
00:16:40 on the label as well.
00:16:42 But now you might be wondering why is nothing showing up right here under gender or date of birth?
00:16:48 Well, that's because we have created two new custom inputs of types date picker and skeleton.
00:16:55 And what we have to do is actually put them to use within our custom form field.
00:17:03 We have to create two new switch cases for those options.
00:17:07 So let's do just that.
00:17:10 Let's do one for the date picker first by adding a new case of form field type dot date underscore picker.
00:17:20 And if that is the case, we can simply return.
00:17:24 A div with a class name equal to flex rounded dash MD border border dash dark dash 500 and BG dark of 400. You can see something is starting to happen.
00:17:41 We can then render an image with a source of forward slash assets, forward slash icons, forward slash calendar dot SVG.
00:17:52 With a height of about 24, a width of about 24, an alt tag equal to calendar and a class name of margin left of two.
00:18:04 Okay.
00:18:05 That's looking more like it.
00:18:06 Now let's render the actual form control.
00:18:11 Okay.
00:18:12 And within it, we can render the react date picker.
00:18:16 And of course we won't reinvent the wheel.
00:18:18 We'll again use the react dash date picker npm package.
00:18:24 So you can search for it.
00:18:27 It's going to look something like this, but of course we'll further style it.
00:18:30 But you can install it by running npm install react-datepicker-save.
00:18:37 And then here is how we can use it.
00:18:39 You just import it alongside its CSS.
00:18:42 So let's copy that and paste it right here at the top.
00:18:46 And then you just use it.
00:18:48 So let's copy the usage from here.
00:18:50 And just paste it right here.
00:18:53 There we go.
00:18:53 Date picker with the selected property and then onChange property as well.
00:18:59 So if we go back, of course, these fields will be undefined for now.
00:19:04 So instead of saying selected is start date, we'll say it's field.value because that holds the actual value of the field.
00:19:12 And then onChange won't look like this.
00:19:15 It will rather be.
00:19:17 a function that sets the field dot on change, and then we pass the date to it.
00:19:24 Okay, let's save it.
00:19:26 Perfect.
00:19:27 Now we have something that resembles a good looking calendar picker.
00:19:32 You can see how simple it is.
00:19:33 I mean, I know people who would have maybe started to create this picker by using the default HTML picker component.
00:19:42 It's going to be tough, right?
00:19:43 Like right out of the box, you're getting a phenomenal picker here with date selection, colors, CSS, all that good stuff.
00:19:50 And we can even extend it to add time later on.
00:19:53 So always make use of great packages when you can.
00:19:57 Now let's extend it further by giving it a show time select as well, which will be equal to, and again, we can get this from props right here.
00:20:10 I'll call it.
00:20:12 Show time select as well as the date format.
00:20:17 Okay.
00:20:18 So these are the two props that we're passing and based on these, we can modify not only the type of the form field we're deciding to show,
00:20:27 but also how that specific form field behaves.
00:20:31 So we'll say if date format exists, question mark, question mark.
00:20:37 Then we will format the date like so, MM, which stands for month, forward slash DD, YYYY.
00:20:48 And this was supposed to be date format right here.
00:20:52 We can do a similar thing for the show time select where I'll check if show time select is selected, then we'll do that.
00:21:00 Else we'll return false.
00:21:02 So now you can see there's no time because we didn't pass that prop into this specific date picker, but later on we'll pass it into the appointments picker.
00:21:11 We can also pass the time input label as equal to time like this.
00:21:19 And I'll give it a wrapper class name equal to date dash picker.
00:21:26 This will just give it some additional spacing.
00:21:28 So it looks great.
00:21:30 Wonderful.
00:21:31 Looking good to me.
00:21:32 So the date picker is done, but now let's work on this select or skeleton field.
00:21:37 I will collapse this one just so it's easier to see.
00:21:39 And I will create a new or another case equal to form field dot skeleton where I'll return.
00:21:49 a new thing.
00:21:50 And that thing will simply say render skeleton If it exists, then we will call the render skeleton with the field that we're trying to render,
00:22:03 else we'll render a null.
00:22:05 Okay.
00:22:06 As simple as that, it's going to look something like this.
00:22:10 And this render skeleton is coming from props.
00:22:14 So we can say props right here, or rather I should try to destructure the render skeleton from the props.
00:22:22 Okay, so if we save it, you can see the skeleton for these different types of fields and they're coming from the register form because we have specified
00:22:32 what are we showing right here.
00:22:34 Let's just make sure that all the props are looking good.
00:22:37 So it's going to be a radio group with a flex property, H11, gap of six, and then an extra large devices justified between with a radio group and a label.
00:22:48 Yep, that's looking good to me.
00:22:51 So if we go back, the skeleton is looking good as well here.
00:22:55 And we can actually select different options.
00:22:57 It seems like the cursor pointer is not being applied on the label.
00:23:01 So let's go back here and see cursor pointer.
00:23:06 Yeah, it was supposed to be pointer.
00:23:08 Okay.
00:23:09 Yep.
00:23:10 And now it is better, but you can see the circle doesn't really fill the entire space.
00:23:15 Oh, that's most likely because of my zooms.
00:23:18 Yeah.
00:23:18 So on a hundred percent zoom, it should work perfectly.
00:23:21 Yep.
00:23:21 That's good.
00:23:23 I'm going to zoom out again, just so we can see how it looks like on desktop devices.
00:23:27 There we go.
00:23:29 And as you can see, everything is completely mobile responsive.
00:23:33 Now we can collapse this custom form field and we can continue adding more.
00:23:39 Let's compare that with the design.
00:23:42 Now we're ready to move over to medical information.
00:23:46 So let's do that next.
00:23:49 We'll most likely need to add another subheader.
00:23:51 So I'll copy this section with a heading and paste it right below this div containing this skeleton for gender.
00:24:00 So now we can see medical information.
00:24:05 Okay, that's good.
00:24:06 Oh, but I noticed there's a slight mismatch in the design and how it should actually look like.
00:24:11 So I'll most likely fix this design by the time you're watching this, but for now, you can just follow my lead.
00:24:17 We won't yet display this medical information.
00:24:20 It will go a bit later because there's still some information we need to collect about user's personal info.
00:24:27 So let's just proceed with the next div right here.
00:24:31 And we'll try to get the address.
00:24:33 Okay.
00:24:34 So let's just copy the first two inputs, the regular ones, which are just of a type input.
00:24:40 That's going to be this one for the email.
00:24:44 And we can just duplicate it two times right here.
00:24:48 And now we can exchange them for whatever we need in this case.
00:24:51 Let's make that name of address.
00:24:54 Label will be address.
00:24:57 Placeholder will be something like let's do 14th street, New York, and we don't need any icons.
00:25:07 For the next one, we'll do occupation.
00:25:10 So let's say occupation and label will be occupation as well.
00:25:15 With a placeholder of software.
00:25:18 engineer.
00:25:19 Okay.
00:25:20 And if we save it, pretty simple, right?
00:25:23 Works great.
00:25:24 Now we can go down and we can render a few more.
00:25:27 This time I want to render an input and a phone picker.
00:25:33 So I'll copy these two that I have, phone input and the input.
00:25:37 And I will just paste them within this next div right here.
00:25:42 So that's going to be input and it's going to be emergency.
00:25:47 contact name with the label of emergency contact name, and the placeholder will be something like guardian's name.
00:26:03 Okay.
00:26:04 And we can also add the phone number.
00:26:06 So the name here will be emergency contact number, and the label will be emergency contact number as well.
00:26:19 Perfect.
00:26:20 So now we have that out of the way as well.
00:26:22 You can see how simple it is to just keep building on UI elements once you have created a reusable component.
00:26:29 Okay.
00:26:30 And now we can render this section for medical information.
00:26:36 Once we have collected all the base information.
00:26:40 So let's put it here and uncomment it.
00:26:43 That'll be a section that's going to say medical information.
00:26:48 There we have it.
00:26:49 Now we want to render a specific field and it will be a field for selecting primary care physician.
00:26:57 So this is a complicated selector field where you can select from a list of doctors.
00:27:03 Okay.
00:27:04 So we haven't yet had a select field and now we'll develop one.
00:27:09 So let's do it right here outside of this div by rendering a typical custom field.
00:27:15 So we can copy it and paste it here.
00:27:18 But this time it will actually say something like form field dot select with a control of control name will be equal to primary physician.
00:27:33 And again, make sure that all of these are spelled properly because how you name them here will actually save them that way in the database.
00:27:41 And we need this to match AppWrite's structure that we have created before.
00:27:46 Label will be primary physician as well.
00:27:49 And the placeholder will be select a physician.
00:27:55 Okay, simple enough, but now we can pass additional children into this custom form field.
00:28:03 That's how extensible our component is.
00:28:05 We can do it like this and then have a list of doctors that we can then render like Dr.
00:28:12 John Doe, Dr.
00:28:13 Jane Doe, and so on within an array.
00:28:18 It's going to look something like this, but of course we want to give each doctor an image and just make it look a bit better.
00:28:25 So I prepared a list of a couple of doctors.
00:28:28 You can just open up the GitHub repo and then go to constants index.ts and copy the full constants file.
00:28:38 Then navigate over to constants in the code.
00:28:42 and simply override everything we have right here.
00:28:45 You can see the doctors there.
00:28:47 It's basically a list of images and names.
00:28:50 This would be a great thing for you to expand on later on once we finish the development of this application.
00:28:56 So you can actually allow the admin of this healthcare management platform to add new dynamic doctors to the list.
00:29:05 With that said, instead of mapping through these fake doctors, we can get access to the doctors from the constants by saying doctors coming from constants.map
00:29:18 and we get each individual doctor.
00:29:20 And for each doctor, we can render a select item coming from UI select.
00:29:26 Each one has to have a key.
00:29:28 And it'll be equal to a doctor.name since each doctor has a different name.
00:29:34 And the value when clicked will be doctor.name as well.
00:29:39 We can also render a div within each one of these.
00:29:44 And that div will have a class name equal to flex cursor dash pointer.
00:29:52 items-center and a gap of two.
00:29:56 Within it, we can render a self-closing image that will have a source equal to doctor.image with the width of 32, a height of 32 as well,
00:30:10 an alt tag of doctor.name.
00:30:12 And a class name equal to rounded-full, which is what we typically do with avatar images, border, and a border of dark 500. Okay.
00:30:25 Let's save it.
00:30:27 Make sure to import the image from next image if it hasn't been imported already.
00:30:32 And below that image, we can render a p tag that will render the doctor.name.
00:30:39 Let's save it.
00:30:42 And right now under this medical information and primary physician, there's nothing there because we haven't yet implemented the select functionality.
00:30:53 So let's go to the custom form field and create a new case right here below the date picker for the select by saying case form field type.
00:31:06 dot select, and we can return something.
00:31:10 By something, I mean a form control that'll render a select coming from UI select with an on value change equal to field dot change.
00:31:25 And a default value equal to field that value.
00:31:30 We can also render the form control within this select and give it a class name equal to shad dash select dash trigger.
00:31:41 And within it, we can render a select value with a placeholder equal to placeholder.
00:31:48 Okay.
00:31:50 And make sure to import select value from UI select.
00:31:55 So if we save this and properly close this select value, You can see select a physician label.
00:32:04 So this will allow us to actually select a physician.
00:32:07 We can exit this form control and create a select content.
00:32:12 Okay.
00:32:13 Coming from UI select that'll have a class name equal to shad dash select dash content.
00:32:21 And here we'll render the props dot children.
00:32:25 So whatever we have created in the register form here, we now want to show within select content as children.
00:32:33 So let's save it, reload the page, and let's check it out.
00:32:38 Right now, if I click primary physician or select a physician, nothing really happens.
00:32:44 That's because instead of field.change, I was supposed to say, feel that on change right here on the value change because it's a handler,
00:32:54 but it's still not selecting it.
00:32:56 And that's because I forgot to wrap the select value into a select trigger.
00:33:01 We have to trigger the select so we can get the select trigger from UI components and then put the select value right within it.
00:33:10 And then this class name of ShadSelectTrigger will actually go on the trigger itself and not the form control.
00:33:19 There we go.
00:33:20 That's more like it.
00:33:21 Now, if we click right here, you can see all of these different doctors and you can click on them and one will get selected.
00:33:30 Great.
00:33:32 So we have the select component or select form field working as well.
00:33:38 And again, just keep in mind, we are now working for the first time through building out these custom reusable, different types of form fields.
00:33:48 But imagine once they're all built out, like the next time we encounter a phone input or a calendar input or a selection of a person,
00:33:56 we already have it built out and we just have to just type it out right here and call it and it's going to be a done deal.
00:34:03 Perfect.
00:34:04 Now let's see what else do we have to do on the form.
00:34:08 Let's try to get the insurance policy and number.
00:34:12 We can do that within a div and that'll be two different input fields.
00:34:17 So let's find two different input fields.
00:34:20 For example, here for the address and the occupation, let's copy them and paste them right within the div.
00:34:29 Instead of address, it will be insurance provider.
00:34:33 The label will be insurance provider as well.
00:34:40 And the placeholder will be something like blue cross blue shield.
00:34:46 Typically insurances have those weird kind of names.
00:34:50 And we also need an insurance number.
00:34:52 So that's going to be insurance policy number with a label of insurance policy number.
00:35:01 And we can say something like ABC123456789.
00:35:07 If we save it, this is looking good.
00:35:11 Let's also work on our allergies.
00:35:13 What if we have some allergies?
00:35:15 Well, let's fix that.
00:35:16 I'm going to duplicate this div with the two latest fields we have created right below.
00:35:22 And instead of rendering an input, it's possible we have more allergies or we're taking more of the existing medication.
00:35:29 So let's actually switch this to be a text area component here as well.
00:35:36 And the name will be allergies.
00:35:39 Label will be allergies, if any.
00:35:44 And the placeholder will be something like peanuts.
00:35:47 Let's do penicillin and pollen.
00:35:52 And for the second one, we can say current medication.
00:35:58 We can also say something like current medication, if any.
00:36:03 And under placeholder, we can do ibuprofen, something like 200 milligrams and maybe, I don't know, paracetamol 500 milligrams.
00:36:14 Good.
00:36:15 So now we would be able to see those inputs if we had created a text area before, but we haven't done that already.
00:36:24 So let's move into the custom form field for one of the last times to create a case for the text area.
00:36:32 It'll be pretty simple.
00:36:34 So let's do it right below the input by giving it a case of form field dot text area.
00:36:41 And we can simply return a form control that will render a text area component.
00:36:49 And I do believe that we have to install it as well from ShotsCN.
00:36:53 So let's run MPX ShotsCN UI latest, add text area like this.
00:37:02 And then we'll be able to simply use it by saying text area coming from UI text area.
00:37:09 We can pass a placeholder to it equal to placeholder.
00:37:15 We can also spread all of the other field information, give it a class name of shad text area.
00:37:24 And give it a disabled of let's do props.disable.
00:37:29 So if it's disabled, want to disable it.
00:37:31 And you can see two different text areas, which you can type into.
00:37:35 You can expand.
00:37:37 This is looking great.
00:37:41 Perfect.
00:37:42 Let's see which other fields we want to add below.
00:37:46 Let's actually add two more text areas for family medication and other family medical history by duplicating these two below.
00:37:55 So the last two ones we have created, including the div as well.
00:37:59 And let's change the allergies to family medical history with a label equal to family medical history.
00:38:12 And here we can say something like, let's say mother had a brain cancer and the father had heart disease.
00:38:22 We can also go for the second one and here we can say past medical history.
00:38:30 And we can also just render a label here, past medical history.
00:38:36 And I wanted to include all of these fields in because I know it can be just too much to type them out, but this is how real applications basically look
00:38:45 like and work as well.
00:38:47 So I wanted to give you a real overview of how real applications look like and how their code bases look like once you actually dive in.
00:38:55 Here we can say something like appendectomy and tonsillectomy.
00:39:00 Good.
00:39:01 And finally, we can also copy this section to create one last section below these two.
00:39:11 And we'll call it identification.
00:39:18 and verification.
00:39:19 Okay.
00:39:20 And save it.
00:39:22 That's good.
00:39:23 So what we want to do here is actually allow people to type out the type of their identification document, its number, and then provide a scanned copy
00:39:37 of that document so we can verify it.
00:39:39 So let's do that next.
00:39:41 Right below this section, I'll duplicate one of the previous select fields we had, as this one will also be a select field.
00:39:49 So let's find a select.
00:39:52 There we go.
00:39:53 It is right here.
00:39:54 It was select a primary care physician.
00:39:57 So let's copy it.
00:40:00 And let's paste it right here, but we'll change a couple of things.
00:40:05 The name will be identification type and the label will say identification type.
00:40:14 Placeholder will say something like select identification type.
00:40:20 Okay.
00:40:20 Pretty simple, right?
00:40:22 That's going to look something like this, but hey, we're still seeing doctors.
00:40:26 So instead of mapping over doctors, we now want to map over identification types coming from constants.
00:40:35 I'm going to say type right here, and it's going to be even simpler.
00:40:39 We don't have to show all of these things.
00:40:41 We can simply show a select item.
00:40:45 Okay.
00:40:45 So let's remove everything besides a select item.
00:40:51 It will render a type and it will have a key equal to type and the value equal to type as well.
00:40:59 So if we save it, select an identification type, and you can see all different kinds of types we can select.
00:41:07 that are coming from our constants.
00:41:10 If you're not supporting some, you can just remove them, but I think this is good.
00:41:14 We're giving people a lot of options.
00:41:16 And after that, we can have one more input and one more skeleton.
00:41:20 So let's find where we have that right here.
00:41:24 Let's just take the input first and paste it just below.
00:41:28 We're going to modify it a bit to say identification number.
00:41:32 with the label being identification number.
00:41:36 And we can do 1, 2, 3, 4, 5, 6, 7, 8, 9 for the placeholder.
00:41:42 Let's also indent it properly.
00:41:45 That's good.
00:41:46 And finally, we want to deal with the file upload so they can scan their document.
00:41:51 And for that, we'll use a skeleton type because it allows us to pass anything we want.
00:41:57 So let's actually copy this skeleton type.
00:42:01 So I can show you how versatile it is.
00:42:03 Before, we used it for the radio buttons right here.
00:42:08 But this time, we'll do something entirely different.
00:42:11 So keep everything in this custom field besides everything that is inside of the render skeleton.
00:42:18 Okay?
00:42:18 So you can remove everything inside of there, and then we can completely change the way it looks.
00:42:24 Like for this one, the only thing we need to do is render a form control.
00:42:29 And within it, we'll later on add a file upload.
00:42:34 But of course, don't forget to change the name to identification.
00:42:39 document and also here say scanned copy of identification document.
00:42:48 So now if we scroll down, you can see scanned copy of identification document.
00:42:53 And for this one, we'll also use a third party package, but we'll just tweak it a bit before using it.
00:42:59 So we're going to create a new component called file uploader.
00:43:06 dot TSX, we can run RAFCE inside of there.
00:43:11 And that means that we can call the file uploader right here.
00:43:16 File uploader coming from dot dot slash file uploader.
00:43:22 And for this one, we'll use a package called react dash drop zone.
00:43:27 It's a great package that allows you to very simply implement drag and drop image functionalities.
00:43:32 So let's just install it by running npm install dash dash save react drop zone.
00:43:39 And here we have the entire usage.
00:43:41 We can basically just copy this hook usage.
00:43:44 So copy it and paste it right here.
00:43:48 Couple of things we'll have to change is that we are working with Next.js.
00:43:52 So we have to add a use client directive at the top.
00:43:56 And of course we'll turn it into a regular export const file uploader.
00:44:03 That's going to be an arrow function.
00:44:05 So that's going to look something like this.
00:44:09 And we'll make it accept files and on change that we'll pass into it of a type file uploader props, which we can define right here at the top.
00:44:22 So that's going to be type file uploader props is equal to files is an array of files.
00:44:33 And onChange is a function that accepts files.
00:44:37 That's basically it.
00:44:39 And maybe sometimes at the start, the file will be undefined so we can define it just like so.
00:44:44 Perfect.
00:44:45 So we're accepting that.
00:44:46 And now we want to do something once we drop the files.
00:44:50 And the only thing we'll do is we'll say onChange and we'll pass the accepted files onto the onChange, which means that we'll just pass them along and
00:45:00 just make them come to where they need to be.
00:45:03 Also accepted files is if we type file array, just so he doesn't complain.
00:45:09 Okay, good.
00:45:10 Now let's modify the UI a bit to make it look better because if I go back here right now, let's see where we are.
00:45:19 Oh yeah, something is definitely breaking.
00:45:22 Let's open up the inspect element and check out the console.
00:45:26 It seems like we're not importing the component properly because this is just a named import now, but hey, we can switch that.
00:45:33 Let's make it a default import.
00:45:36 by just adding export default file uploader to the bottom.
00:45:43 If we do that and reload, we can see our uploader and this is how it looks like.
00:45:48 Drag and drop some files here or click to select files.
00:45:52 Let's make it look just a tiny bit better.
00:45:54 We'll give this div a class name equal to file-upload.
00:46:04 And that already looks so much better.
00:46:06 Again, if you're wondering what this style is or where it is coming from, just go to search, type it out, and check it out here.
00:46:14 We're just applying some border dashed, border colors, and just centering everything using Flex.
00:46:21 Let's also show some images if we do upload them.
00:46:24 So I'm going to say if files exist and if files?length is greater than zero, that means that some files exist.
00:46:34 So we'll try to render an image, of course, coming from next image.
00:46:41 with a source convert file to URL coming from libutils to which we'll pass files and then zero.
00:46:53 We can also give it a width of about a thousand, a height of around a thousand and give it an alt tag of uploaded image and a class name of max-h-400 pixels.
00:47:11 overflow-hidden and object-cover.
00:47:16 So if we do upload an image, it'll show here.
00:47:20 Else, if we don't have any images, we can render an empty react fragment that'll render another image.
00:47:26 This will be a placeholder image.
00:47:30 with a source equal to forward slash assets, forward slash icons, forward slash upload dot SVG with a width of about 40, a height of about 40 and an alt
00:47:43 tag of upload.
00:47:44 Okay.
00:47:45 That's looking better already below it.
00:47:48 We can also add a div with a class name equal to file dash upload underscore label.
00:47:57 and within it a p tag equal to class name equal to text-14-regular.
00:48:06 In here, we can render a span with a class name equal to text-green-500.
00:48:13 And it can say click to upload.
00:48:18 And then outside of this span, we can say, or drag and drop.
00:48:22 And below that p tag, we can render another p tag that's going to say something like different types of files that we can add.
00:48:30 Like SVG, PNG, JPEG, or GIF.
00:48:36 And it's going to be max 800 by 400. I think that is the limitations here.
00:48:42 It should be good.
00:48:43 Anyway, we can now remove this is drag active.
00:48:47 And you can see how this looks much better than before.
00:48:51 Perfect.
00:48:52 With that, our file uploader is done and we can go back here and pass it all the necessary props.
00:49:00 In this case, the files will be equal to field.value.
00:49:04 So notice how we're not storing anything in the state, rather we're using react hook form to keep track of the values and the onChange will be equal to field.onChange.
00:49:17 Perfect.
00:49:18 Finally, to conclude it all, we have to have a few mandatory check boxes, right?
00:49:24 For consent and privacy.
00:49:26 So let's duplicate our section right here below.
00:49:34 And let's call it exactly like that.
00:49:38 That's going to be.
00:49:40 consent and privacy and below it, we can render a few custom form fields of a type checkbox.
00:49:48 So custom form field that'll have a field type equal to form field dot checkbox with a control equal to form control.
00:50:04 A name equal to treatment consent, a label equal to I consent to treatment.
00:50:13 And we can duplicate it two more times.
00:50:16 For the second one, we can say disclosure consent.
00:50:19 So disclosure consent.
00:50:23 And here we can say something like I consent.
00:50:26 to disclosure of information.
00:50:28 And finally, the last one will be something like privacy consent, which means I consent.
00:50:37 to privacy policy.
00:50:39 There we go.
00:50:41 If we save it and go back, you won't be able to see any of these checkboxes.
00:50:46 And that's because we are yet to create the last possible case of our switch statement for different form fields.
00:50:55 And that is a case of form field dot checkbox.
00:50:59 So let's create a form control right here, create a div within it with a class name equal to flex items-center and a gap of four.
00:51:13 And I think we'll have to install a ShadCN checkbox.
00:51:16 So that's going to be install ShadCN LigadistAdd checkbox.
00:51:24 And then we'll be able to import it at the top by saying checkbox coming from UI checkbox with an ID equal to name.
00:51:35 a checked property equal to field.value and an unchecked change equal to field.onChange.
00:51:45 And the name is a taken name.
00:51:47 So we have to do props.name in this case.
00:51:51 And finally, we can show a label for that checkbox because now you should be able to see just three checkboxes.
00:51:58 But if we add a label, with an HTML4 property equal to props.name and a class name equal to checked or checkbox-label, we can render the label right within it.
00:52:19 Or I think that's going to be props.label.
00:52:22 So if we save it, we should be able to see something here.
00:52:26 Oh, but I forgot to return the statement.
00:52:28 Oh, that's a tough one.
00:52:30 Never forget to return something.
00:52:33 That's good.
00:52:34 There we go.
00:52:34 That's much better.
00:52:36 I consent to treatment, disclosure information, and privacy policy.
00:52:41 This is looking good.
00:52:42 And that was my friends, a long form.
00:52:46 Typically how forms look like in these types of applications.
00:52:50 So now I want to full screen this and check out how it looks like.
00:52:56 Okay.
00:52:58 Good.
00:52:59 Let's compare it with the design.
00:53:01 It should go all the way from the left side with much less space on there and almost go to the image on the right.
00:53:08 And in our case, there's a lot of space on the left side.
00:53:11 So let's see what that is about.
00:53:14 By going all the way to the page, this is the register page, and we have to see whether I have properly done the sections.
00:53:22 So first we have flex H screen, max H screen.
00:53:26 We remove the scroll bar.
00:53:27 Oh yeah, I don't need my auto here because we want the starting content to take more space.
00:53:34 Specifically, we'll give it a max W of 860 pixels, which is more than we have on the homepage.
00:53:42 And we'll give it a flex one flex dash coal and padding Y of 10. With these changes, I believe it will look better.
00:53:51 So if we go back, oh yeah, this is the form that we need.
00:53:55 You can see that the image sticks to the right side and the form moves, which is great.
00:54:03 Also, I don't think we need to show the admin here.
00:54:05 We only needed to show that at the start.
00:54:08 So let's go back and we can remove this entire div, but rather just shift the P tag outside.
00:54:16 This is good.
00:54:17 So we don't need the additional admin stuff.
00:54:20 Yep.
00:54:21 This is good.
00:54:22 And then if we exit out of the section, we have the image.
00:54:26 Let's check it out.
00:54:28 Yeah, this is much better.
00:54:30 We can also just give it a bit of divide from the button.
00:54:34 So if we go here, this B tag can just have a property of copyright and padding Y of 12. So if we go back, yep, this is now much better and we have a great
00:54:48 looking form.
00:54:50 So now that the UI of the form is done, let's figure out how we'll submit it and how we'll save all of this information to the database.
00:54:59 Let's go into the register form and scroll to the onSubmit function.
00:55:05 Of course, right now, this is the onSubmit function of the previous form, the patient form.
00:55:10 So we'll have to do some tweaks.
00:55:12 First of all, when it comes to the validation.
00:55:15 Right now, we're still using the old user form validation, but in this case, we want to have a more robust validation for all of the fields that are there.
00:55:25 And I believe that is the last file that we need to get from these snippets, the complete validation, just so we don't have to type it out by hand.
00:55:33 So you can copy it and override the existing validation.
00:55:36 And as you can see, here we have validation for all of these fields that we have created.
00:55:43 Great.
00:55:45 So now, instead of saying user form validation in these three places, we'll simply say patient form validation coming from lib validation.
00:55:55 When it comes to the values, we can keep these three, but then spread all of the patient form default values.
00:56:05 And I do believe that we have those in our constants.ts.
00:56:10 If you scroll all the way up, you have patient form default values.
00:56:14 So we just have to import them.
00:56:15 Let's do that right now.
00:56:18 All the way from constants, we can import patient form default values.
00:56:24 There we go.
00:56:25 And now our form fields are looking good.
00:56:28 It's only the onSubmit that we have to modify because no longer are we creating a user.
00:56:34 Now we're appending additional data to that user.
00:56:38 So let's modify the onSubmit form.
00:56:42 We have to collect all of the data, store it in a way that makes sense, and then send it over.
00:56:48 So let's create a new object called form data that we'll use for storing all of those values.
00:56:54 And no longer do we have just name, email, and phone.
00:56:57 Now we'll just call it values.
00:57:01 We're gonna do a simple check and see if values.identificationDocument exists.
00:57:09 And if values.identificationDocument.length is greater than zero, in that case, it means that we have an actual file, okay?
00:57:21 So this is now regarding the file upload, because before we can append all of these values together, we have to extract the file.
00:57:29 So let's do that first.
00:57:31 To do that, there's something known as a blob and blob is a special version of the file, which a browser can read.
00:57:39 So let's say blob file is equal to new blob to which we can pass values.identificationDocument zero.
00:57:50 And then we can also define the options, which in this case will be type of values.identificationDocument.type.
00:58:01 Once we have that, we can say form data is equal to new form data, and we can append that blob by saying form data dot append blob file,
00:58:13 and we can then add a blob file, and we can also append the file name by saying form data dot append file name, and then we can add values dot identification
00:58:28 document zero dot name and let's spell append properly.
00:58:34 Great.
00:58:35 So this will actually ensure that we have the file saved.
00:58:39 Once we know that we have the file, we can then open up a new try and catch block.
00:58:45 And we need to form all of this data in a way that makes sense for AppRight to receive it.
00:58:52 So const patient data is equal to an object.
00:58:57 And here we can define the user ID is equal to user dot dollar sign ID.
00:59:03 Then we have all of the other fields like name, which should be the values dot name and so on.
00:59:08 I don't want to type out each and every single property like this, email is values.email and so on.
00:59:16 So what I'll try to do is I'll try to spread all of the values and then we'll need to modify only the ones that actually change,
00:59:25 such as the user ID.
00:59:26 It's not ID, it's dollar sign ID.
00:59:29 Okay.
00:59:30 Also, the birthDate will be equal to newDate, as it's not a string, so we need to do it like this.
00:59:37 newDate values.birthDate.
00:59:40 Also, for the identification document, it won't be equal to just a string of something.
00:59:46 It'll be equal to formData, which we created above.
00:59:50 And once we have that patient data, we can say const patient is equal to await register patient to which we pass the patient data.
01:00:03 And then we do a similar thing with it before.
01:00:05 If there is a patient, then call the router.push.
01:00:10 And this time we're going over to forward slash patients, forward slash user.dollar sign ID, forward slash new appointment.
01:00:21 So moving from the homepage to the registration to the new appointment.
01:00:26 And of course, this register patient is another server action.
01:00:30 So let's move over to patient.actions.ts and let's create a register patient server action.
01:00:39 We can do it by saying export const register patient.
01:00:44 Is equal to an async server action that accepts the identification document and all the other information about that patient.
01:00:56 That's if they type register user perhaps like this.
01:01:00 Okay.
01:01:02 That's looking good.
01:01:03 Then we can open up a try and catch block.
01:01:07 If something goes wrong, we can simply console.log this error.
01:01:13 And if everything is going well, we can try to upload that file.
01:01:18 So here's the thing.
01:01:19 We first have to upload the file to be able to access it later on using the URL and then store it.
01:01:25 For that, we're using the AppWrite storage, not AppWrite database.
01:01:29 You cannot simply upload images to the database.
01:01:32 You have to store them somewhere.
01:01:34 So here we're actually working with AppWrite storage.
01:01:39 Let me show you how it works.
01:01:41 First, we can define a file, which is just an empty variable for now.
01:01:46 We're going to check if the identification document exists.
01:01:51 Then we want to get access to that input file from the blob by saying const input file is equal to input file.
01:02:03 And this is coming from node app, right?
01:02:05 So we can import input file.
01:02:10 coming from node app, right?
01:02:14 And that's going to be file.
01:02:18 As you can see, it exposes this input file and we can get a file from a buffer, which is typically a blob.
01:02:25 So right here, we can say input file dot from buffer.
01:02:30 And then to it, we can pass the identification document, question mark dot get blob file as blob.
01:02:41 And in the second parameter, we can pass identification document dot get.
01:02:46 And here we can get the file name as string.
01:02:50 And once we do all of that, we can say file is equal to await storage coming from app right config dot create file.
01:03:01 to which we need to pass the bucket ID, and we're exporting this from AppWrite config as well.
01:03:08 We need to pass the ID coming from AppWrite.unique.
01:03:13 So we're giving this storage file an ID.
01:03:17 And finally, we need to pass the input file itself.
01:03:21 Perfect.
01:03:21 So now we're adding that file to the storage.
01:03:25 Once we add the file to the storage, we then need to create a new patient document.
01:03:31 So let's say const patient is equal to await databases coming from apriconfig.createDocument.
01:03:43 And we need to pass the database ID.
01:03:46 So that's going to be database underscore ID.
01:03:50 We also need to pass the collection we're trying to update.
01:03:53 So that's going to be patient collection ID.
01:03:56 And we also need to pass a unique ID.
01:03:58 So ID dot unique.
01:04:01 that we want to create that's going to look like this, and then we need to pass all of the information for that specific person.
01:04:10 Of course, we'll pass the identification document ID which will be equal to file?$id or null and will pass the identification document URL equal to,
01:04:26 now bear with me, it'll be a string where we get to the endpoint, so this is the AppWrite endpoint, forward slash storage.
01:04:38 forward slash buckets, forward slash bucket ID, forward slash files, forward slash file dot dollars and ID, forward slash view question mark project equal
01:04:55 to project underscore ID.
01:04:58 And this will give us the identification document URL so we can access it.
01:05:03 And of course, let's not forget to spread out all of the other patient data.
01:05:08 Let's call this a new patient since we're already getting the patient data at the top.
01:05:13 Perfect.
01:05:14 Once we have the new patient, we can return parse stringify this new patient.
01:05:21 And now we have a register patient server action that we can call within our register form.
01:05:29 So it's imported from lib actions, patient action.
01:05:34 And this patient data needs to adhere to our form.
01:05:39 Right now it says that there's a mismatch.
01:05:41 It's saying that allergies is an optional in type here, but required in register user params.
01:05:49 Okay.
01:05:50 That's interesting.
01:05:51 So we need to look into these allergies right here.
01:05:54 If we go into the register patient, here we have register user programs and we're expecting the allergies to be either a string or undefined.
01:06:05 But when we define the allergies before, I think that is in the actual form validation here.
01:06:14 Let's see what we said for the allergies.
01:06:16 We said they're optional.
01:06:18 I think that's good.
01:06:19 So I'm not exactly sure why TypeScript is complaining in this case.
01:06:24 For now, we can just run a tsignore for this line.
01:06:29 I believe we should be good.
01:06:30 And now we can give it a shot.
01:06:32 We can fill all of this out and see if it works.
01:06:35 So let me close all of the open files and go back to the browser.
01:06:39 Back on localhost, I'll start filling this data out.
01:06:43 I'm going to enter some random phone number right here, some random date of birth as well.
01:06:50 Let's make it male.
01:06:52 Let's give it a random 14th street New York address.
01:06:58 I am a software engineer.
01:07:02 Let's add a guardian's name or let's try to submit to see what happens if we didn't add these things.
01:07:11 And you'll notice that it actually submitted, which is not ideal because we want to have some sort of validation happening right here.
01:07:18 So let's quickly check that validation right here.
01:07:20 If I go to register form, we are looking at the patient form validation.
01:07:28 And it does have a lot of these strengths, which are not optional.
01:07:33 Some of them are, but you can see that for example, insurance provider needs to be there and many other properties need to be there as well.
01:07:41 So let's see why it doesn't validate it.
01:07:44 If I press submit one more time or get started.
01:07:47 Oh, there we go.
01:07:48 The validation actually happens.
01:07:50 That's good.
01:07:50 So now we can see which fields are mandatory.
01:07:53 Let's actually fill it out one more time by entering all of my properties.
01:07:59 Okay, date of birth, street, software engineer.
01:08:04 Let's enter a test name right here.
01:08:08 I guess we can repeat the phone number right here.
01:08:10 That's another interesting check to make.
01:08:12 If you wanted to make sure that these are not the same, you can do that.
01:08:16 Primary physician, and we can just enter some random test values for these.
01:08:24 Allergies, let's do peanuts.
01:08:28 Fun fact, I am actually allergic to peanuts.
01:08:32 We can enter some current medication, we can maybe say none, and we can try to upload a file.
01:08:39 So let's give that a shot.
01:08:41 I'll upload a random fake ID photo right here.
01:08:45 That should be good.
01:08:46 McLovin.
01:08:47 And I'll consent to all of these check boxes.
01:08:50 And let me try to click get started and see what happens.
01:08:55 I'll click get started.
01:08:56 It's loading and...
01:09:00 Oh, it seems like nothing has happened.
01:09:03 Let's see what that is about.
01:09:05 Back in the terminal, I got an invalid document structure, attribute identification document has invalid type, must be a string and no longer than a hundred characters.
01:09:18 So if we go back here, it looks like I actually forgot to provide that.
01:09:22 So let me add it right here.
01:09:24 It's good to know that works.
01:09:26 And let me click get started.
01:09:29 It's loading, but still nothing.
01:09:32 Let's see if we get something else right now.
01:09:35 This time we get an identification document URL, which is empty.
01:09:40 So it looks like the upload didn't properly happen.
01:09:43 Because if you remember, the identification URL is coming right from here when we upload it.
01:09:50 So let's see how we're passing it in the register patient.
01:09:54 We are passing the identification document URL.
01:09:59 And that is exactly what it's expecting, but it looks like for some reason it's not accepting it.
01:10:06 Let's make sure it's spelled properly.
01:10:09 It's identification document URL.
01:10:13 And right here also identification document URL.
01:10:18 Is it possible that when we spread the patient that it's overriding the identification document?
01:10:24 I doubt it because the patient shouldn't have the URL right here.
01:10:27 Yeah, it just has the type, number and document, not the actual URL.
01:10:32 So let's try to console log the identification document ID and URL just before we try to create a patient to see how those values actually look like.
01:10:43 Go back and click get started, which should trigger another message.
01:10:48 And there we have it.
01:10:49 So the identification document ID is good and the identification document URL also looks good, but it's complaining that it should be no longer than a
01:11:00 hundred characters.
01:11:02 Oh my God, is this actually longer than a hundred characters and that's why it's breaking?
01:11:06 We might need to go back to AppRite, back to databases, the patient collection, attributes, and we might need to make our identification document URL longer
01:11:20 than a hundred characters.
01:11:21 And to do that, I think that we need to delete it and create it from scratch.
01:11:25 So let me do it by going here and deleting it.
01:11:32 And creating it one more time has a string, identification document URL with a size of 1000 this time.
01:11:40 I think that should be enough.
01:11:43 Perfect.
01:11:45 Going back, I'll try to just submit the form one more time.
01:11:51 Get started and...
01:11:54 Oh, it looks like it passed, but now it's complaining about gender.
01:11:59 Yeah, it's still stuck at gender, but at least we know that we passed this 100 character limit.
01:12:04 So we can remove this console log and we can see what is happening with the gender.
01:12:08 It says right here, invalid structure, value must be male, female or other.
01:12:14 Okay.
01:12:15 Let's see what we have in our select field for the gender.
01:12:19 So if I go to gender and I go to gender options, oh, it has a capital M, F and other.
01:12:27 So I'm just going to fix this to be male, female and other with a lowercase letter.
01:12:32 Yep.
01:12:33 Sometimes you have to be that careful.
01:12:35 So that's why I've been telling you that you have to have all of these names properly spelled out.
01:12:41 Okay.
01:12:41 Let's click get started.
01:12:43 And we seem to have another issue this time.
01:12:47 Still with the gender, it looks like the value is not coming along properly.
01:12:52 So before we create a patient, let's also console log the gender by saying console.log gender is, let's do patient.gender to see what it is.
01:13:06 So if I go back and click get started, I should be able to see this value of gender.
01:13:14 somewhere at the top.
01:13:15 Oh, it's still a capital M.
01:13:18 Okay.
01:13:18 This is good to know.
01:13:19 So you have seen me make a change to the gender options, the lowercase, right?
01:13:24 But this change is on the front-end side.
01:13:28 And if you make a change on the front-end side, you have to reload your browser.
01:13:32 Okay.
01:13:34 When you make it on the backend, you can just re-trigger another request.
01:13:37 But when you make it on the front-end, you have to reload your browser.
01:13:42 I also noticed that the default here also needs to be a lowercase m.
01:13:47 So we have to reload it and all of our information will get canceled.
01:13:51 So I'll speed this process up for you, type some values in, and then we'll try once more.
01:13:57 Okay.
01:13:58 Here I am consenting to the last check boxes and pressing get started.
01:14:03 Oh, it looks like I missed the field for the phone number.
01:14:06 So I will add it right here.
01:14:08 And it looks like now my validation is properly working.
01:14:12 So I have to go to my validations and change the validation for the gender right here to be all of these with a lowercase letter.
01:14:25 Okay.
01:14:26 So male, female and other.
01:14:29 And now that I think about it, might've been better to just rename it to the uppercase letter back in the AppWrite dashboard.
01:14:35 But now since we changed it, that's fine.
01:14:38 Let's go ahead and change this.
01:14:40 Okay.
01:14:42 We should be good now and let's click get started.
01:14:46 Loading and we have one more error, I guess.
01:14:50 Going back here, it says unknown attribute primary physician.
01:14:56 Let's see why that is happening.
01:14:58 Primary physician.
01:15:02 It seems to be spelled properly.
01:15:04 But did we spell it properly here?
01:15:06 Primary.
01:15:08 Oh, there we go.
01:15:09 This is what I've been telling you.
01:15:10 If there's a mistake here, right?
01:15:12 It's not going to work.
01:15:14 So we have to delete this property and recreate it once again in the dashboard.
01:15:19 Hopefully you spelled it right.
01:15:21 So primary physician with a size of 100 and create.
01:15:30 So going back, we can try to now re-trigger it.
01:15:33 It's loading.
01:15:34 Let's see what happened now.
01:15:37 Treatment consent is another invalid attribute.
01:15:41 Let's see how we have spelled it here.
01:15:43 Yep.
01:15:43 Definitely not treatment consent.
01:15:45 Let's see.
01:15:46 Consent, privacy consent.
01:15:50 Yeah, there really isn't a treatment consent here.
01:15:52 So we have to add an additional attribute of treatment consent with a size of 100 and it won't be a string, rather it will be a boolean.
01:16:01 So let's add a new boolean of treatment consent and click create.
01:16:07 And I think we have another boolean right here.
01:16:10 It's going to be the privacy policy.
01:16:11 So let's see how we have called that privacy policy.
01:16:17 Okay.
01:16:18 Let's see, the last one is disclosure consent.
01:16:22 Oh, we have treatment, disclosure, and privacy consent.
01:16:26 Okay.
01:16:28 Treatment, disclosure, and privacy.
01:16:31 So going back right here, I'm going to add disclosure consent.
01:16:39 Okay.
01:16:39 So now we have privacy, we have disclosure, and we have treatment.
01:16:44 Okay.
01:16:44 I believe we should be good.
01:16:46 So now I will try it one more time by going back here and clicking getting started.
01:16:53 And there we go.
01:16:54 We are redirected to the new appointment page.
01:16:57 Quite some fixes, but it's a long page with a lot of fields and it's totally normal that some of the things will be misspelled.
01:17:04 So now just to make this new appointment not so underwhelming, we can actually go here and create a new page under patients,
01:17:14 user ID, new folder called new-appointment.
01:17:21 and create a new page.tsx where we can run r-a-f-c-e and call it new appointment.
01:17:32 If we do this and go back, you can now see new appointment at the top, which means that we are ready to start creating the next page,
01:17:41 which will look like this.
01:17:42 Now that you are registered, now that you are a patient in our database, you can choose your doctor and choose a reason for the appointment,
01:17:50 choose a date and submit and continue.
01:17:54 This is going to be the last page on the patient side of things, after which we'll move over to the admin side of things.
01:18:03 So when it comes to the patients, this form will now be as easy as it can be because we have already created all of these inputs and we just have to create
01:18:14 another form, reuse them and call it a day.