
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 dive into the process of creating an appointment form using TypeScript, focusing on modifying default values, structure, and functionality to ensure a smooth user experience. The session covers practical examples of form field creation and adjustments, validation, and establishing relationships with the backend database for effective appointment management.
00:00:00 So let's do just that.
00:00:02 To start working on the appointments form, we can refer to the original form we've had.
00:00:07 That's not the register form, but the other one.
00:00:10 But while we're here, we can just fix this issue with the default values.
00:00:15 You can see the gender here is confusing our TypeScript.
00:00:17 So we can go into the patient default values and just change this gender thing to male, female, and other with lowercase letters.
00:00:29 Great.
00:00:30 So now everything is good and we can go over to our homepage because this was the original form.
00:00:37 So let's go ahead and copy this entire page and paste it into the new appointment.
00:00:43 Of course, make sure to change the name to new appointment.
00:00:47 And we can make small tweaks to make it look like an appointment page.
00:00:51 The top part will remain the same.
00:00:53 Remove scroll bar, container, and my auto.
00:00:57 We can have a longer width of about 860 pixels.
00:01:01 Flex dash one and justify dash between.
00:01:06 Next, we have a full logo.
00:01:08 Instead of the patient form, we'll render an appointment form here.
00:01:12 More on that later.
00:01:14 And we don't need this div, we just need a P tag that says Care Pulse.
00:01:19 So we can remove the link and the other div.
00:01:23 And then at the bottom, we have the appointment image, which is different from the original image.
00:01:29 So appointmentimg.png.
00:01:32 And the max W will be 390 pixels and the BG of bottom.
00:01:39 And it's going to say appointment.
00:01:42 If we save this and go back, you can see that it looks something like this.
00:01:47 And now we can create the appointment form.
00:01:50 So let's go to forms and create a new appointment form.tsx.
00:01:58 And we'll actually use the patient form as the baseline for the appointment form.
00:02:03 So we can just paste it and we can import it within this page by calling it appointment.
00:02:11 form and of course we have to change the name in the appointment form so if we go to appointment form we have to rename it from patient form to appointment
00:02:25 form and we can rename it here as well and remove these form field types as we don't need them in this file rather we will import them coming from patient
00:02:37 form Okay, good.
00:02:38 So now, let's import the appointment form and see how it looks like in the browser.
00:02:44 Okay, that's good, but of course we have to change the actual fields to be doctor, reason for appointments, additional comments and notes,
00:02:52 and then expected appointment date.
00:02:55 So let's dive into the appointment form and modify those fields.
00:03:00 Everything should be pretty simple right now as we know exactly what kind of fields do we need and we have already developed all of them.
00:03:08 So right at the top, we can say something like new appointment.
00:03:15 And we can say something like request a new appointment in 10 seconds.
00:03:21 And here we can render our first custom form field.
00:03:25 To this appointment form, we'll pass different kinds of props.
00:03:28 And one of the props is the type, whether we want to create an appointment or cancel an appointment.
00:03:34 We also want to pass a user ID, which we can get from params right here by destructuring the params and then destructuring the user ID as well.
00:03:44 And that'll be of a type search-param-probs.
00:03:48 So now we can also pass the user ID is equal to user ID.
00:03:53 And we also need to get access to the patient.
00:03:56 So we need to say const patient is equal to await get patient based on the user ID.
00:04:05 Okay.
00:04:06 So first we have to make this function async.
00:04:09 And now we have to create this server action called get patient that will return as the patient based on its user ID.
00:04:17 So we can do that similarly to getting the user by simply duplicating it.
00:04:23 We're accepting the user ID, and instead of saying user, users.get, we'll say const patients is equal to databases.listDocuments.get.
00:04:42 And here we have to provide a couple of props such as the database ID from which we're trying to fetch the documents from.
00:04:50 Then the ID of the collection we're trying to fetch from.
00:04:54 And finally, the query where the user ID is equal to the user ID we're trying to target.
00:05:01 So that's going to look something like this.
00:05:03 This will return a list of patients that match the query.
00:05:07 And then we can just return patients.
00:05:11 And that's going to be our patient.
00:05:18 So now that we have that, we can import it from LibUtils, get patient, and we can also pass the patient ID to the patient.
00:05:29 to the appointment form so we know which user is booking the appointment.
00:05:34 Let's get into the appointment form and let's accept all of these props such as the user ID, the patient ID, the type, and I think that's it for now.
00:05:49 And those will be of a type.
00:05:51 We can define it here.
00:05:53 User ID is of a type string, patient ID is of a type string, and type is either create or it'll be cancel.
00:06:02 Great.
00:06:03 So now going back down, we can modify our custom fields.
00:06:09 First, we want to open up a new ternary operator and check if type is not equal to cancel.
00:06:16 That means that we want to create it.
00:06:18 And in that case, we can return all of the custom form fields.
00:06:22 We can wrap that in an empty react fragment and then render a custom form field.
00:06:30 And we'll write it together from scratch.
00:06:33 So I might as well remove all of these other form inputs right here.
00:06:38 Just so one time we can see how easy it is to create it once you have actually created a reusable component for it.
00:06:45 It'll have a field type equal to form field type dot select.
00:06:53 Don't forget, this is what we're creating, this doctor select right here.
00:06:58 And if I remember correctly, we have already done this field right here, as well as these two text areas.
00:07:05 So let's get those from the registration form.
00:07:07 I'll navigate over to the register form.
00:07:11 And search for select.
00:07:14 And here we have a doctor selector.
00:07:17 So let me take this part right here.
00:07:20 I'll just grab it and paste it right here.
00:07:25 Of course, we have to import the doctors.
00:07:27 We have to import the select item, the image, and I think that is it.
00:07:33 Let's save it and see how does it look like.
00:07:37 Okay.
00:07:38 That's good.
00:07:39 Perfect.
00:07:40 We might change some of the naming, primary physician.
00:07:43 We'll keep that the same, but we'll change the label to doctor.
00:07:47 And we'll also say select a doctor.
00:07:51 Everything else is looking good to me.
00:07:54 Next, right below this custom form field, still within this empty react fragment, we'll have another custom form field.
00:08:06 This one will have a field type equal to form field type dot date underscore picker with a control equal to form dot control,
00:08:20 a name equal to schedule.
00:08:26 a label equal to expected appointment date, a show time select, because now we want to actually show the time alongside the date,
00:08:38 and a date format equal to mm forward slash dd y y y y, And then HMMAA.
00:08:49 So this is both the date and the time format.
00:08:53 So if I go back, you can see how that looks like.
00:08:56 Pretty cool.
00:08:57 So we can select this and the time.
00:09:00 Great.
00:09:01 Let's also create another div right here and give it a class name equal to flex.
00:09:10 Flex-col gap of six.
00:09:14 And within it, we can render two text area fields.
00:09:17 So I'm going to say custom form field of a field type text area.
00:09:25 Here, we want to choose a reason as the name and the label reason for appointment.
00:09:31 And then add a placeholder, enter appointment reason.
00:09:35 And then the next one can be for the notes.
00:09:38 Now we can exit this dynamic block of code and just do a check if the cancel is true.
00:09:45 In that case, we want to show another text area.
00:09:49 which will look like this, but it will simply say cancellation reason, reason for cancellation, and let's say placeholder enter reason for cancellation.
00:10:00 Perfect.
00:10:01 We can also modify the submit button by giving it the isLoading property and also giving it a class name depending on the state.
00:10:11 So if the type is triple equal to cancel, In that case, we can show a shad-danger-btn.
00:10:22 Else, we can show a shad-primary-btn.
00:10:27 And always, we can give it a W of full.
00:10:31 And instead of rendering, just get started.
00:10:34 It will render a custom label.
00:10:37 So let's create that custom label right here by saying let button label.
00:10:44 And then we can have a switch statement that takes a look at the type of the event.
00:10:52 And if the type is cancel, it'll basically update the button label to say cancel appointment.
00:11:00 If the case is something like create, it'll say something like create appointment.
00:11:06 And if the case is equal to schedule, it'll say something like, I think you can guess it, schedule appointment.
00:11:18 Great.
00:11:18 So now based on these states, we can have custom button labels and it looks like we need to add the schedule right here to the types.
00:11:27 So that's going to be schedule.
00:11:30 Perfect.
00:11:31 And now we can modify this button at the end of the screen by simply rendering the button label.
00:11:40 Great.
00:11:41 Let's save it.
00:11:42 Check this out.
00:11:44 It looks great, but I think we need to add an additional property.
00:11:49 And that is right here under this div, maybe on extra large devices, we make it flex dash row.
00:11:57 So that way they're going to appear one next to another.
00:12:01 That's great.
00:12:02 And also we can modify this 2024 care pulse in this page, just to give it some extra space by giving it a copyright class name,
00:12:14 margin top of 10 and padding Y of 12. So that's going to give it some more space to breathe.
00:12:22 And with this, we should be able to create a new appointment.
00:12:27 So how will that actually work?
00:12:29 Well, you should be the master of forms at this point.
00:12:32 So once you collect all of these values, we're going to go to the form validation.
00:12:38 And in this case, it won't be user form validation.
00:12:41 It'll be appointment form validation.
00:12:47 Make sure to import it at the top from the lib validation and use it in all three places.
00:12:54 Next, we have to set the default values.
00:12:57 They're going to be different here.
00:12:58 So we can say primary physician will be equal to an empty value for now.
00:13:06 Schedule will be equal to just an empty date.
00:13:10 Reason will be empty.
00:13:12 Note will be empty too.
00:13:14 And cancellation reason will be set to an empty string as well.
00:13:17 But let's check what we have here.
00:13:20 Is it note or is it notes?
00:13:23 Let's see.
00:13:24 If I go here, it's going to be notes.
00:13:28 I do believe that AppRite will be expecting note.
00:13:30 So I will switch this over to note as that's what we can add in the AppRite dashboard.
00:13:35 So that's going to be note right here.
00:13:38 And now we can actually submit those values.
00:13:41 So instead of destructuring them, let's just say values.
00:13:45 And we can have three different appointment statuses.
00:13:48 So I'm going to say, let status open up a switch statement.
00:13:52 And if type is equal to schedule, then the status will be set to scheduled.
00:14:00 Again, we need to add this D at the end just to adhere to our form.
00:14:04 And by default, we'll do a status of pending.
00:14:08 Now let's clean up our try and catch block and in the try, if Type is triple equal to create.
00:14:17 And if we have access to a patient ID, we should be able to form what is yet to become an appointment.
00:14:24 So const appointment data is equal to an object that has a user ID.
00:14:32 It has a patient equal to patient ID.
00:14:38 It has a primary.
00:14:40 physician equal to values.primaryPhysician.
00:14:44 It has a schedule equal to values.schedule, but we have to wrap it in a new date object.
00:14:55 We also have a reason equal to values.reason, a note equal to values.node, and a status, which can be equal to status as status.
00:15:10 This will simply be for TypeScript.
00:15:12 And we have to fix the patient ID typo at the top.
00:15:17 Perfect.
00:15:18 So now that we have this, we are ready to send it over to our backend by saying const appointment is equal to await create appointment.
00:15:34 And to it, we pass the appointment data.
00:15:38 That's not going to be create appointment schema.
00:15:40 I'm going to fix that.
00:15:41 So it's just create appointment, a server action, which we have to create right now.
00:15:46 And it'll be similar to register user.
00:15:49 So I can quickly go to patient actions and check out our register patient and copy the part where we're just creating this new patient and returning it.
00:15:59 That's what we need, but it won't be within the patient actions.
00:16:04 Rather, it will be within appointment actions.
00:16:08 So I can create a new appointment.actions.ts.
00:16:15 Within it, we can export const a new create appointment.
00:16:22 Action equal to an async function, and we can open up a new try and catch block there.
00:16:28 In the catch, we can console.log the error.
00:16:32 And in the try, we can paste what we just copied.
00:16:36 So let's import all of these things here.
00:16:39 Databases, database ID.
00:16:42 It won't be patient collection ID, rather it will be an appointment collection ID.
00:16:48 So we can import that.
00:16:50 import ID from Node AppWrite, import endpoint, and we won't need to import these because these are file-related.
00:16:58 So we can remove those parts from here and import, parse, stringify.
00:17:04 Great.
00:17:05 Now, instead of getting access to the patient data, we'll be getting access to the appointment data.
00:17:11 So we can say appointment.
00:17:14 of a type create appointment, perhaps we'll call it new appointment.
00:17:20 And as the data will pass all of the appointment information coming from the front end.
00:17:27 Finally, we can return par stringify.
00:17:33 Going back to our appointment form, we can now bring this line back and import create appointment from lib actions, appointment actions,
00:17:43 to which we pass the appointment data.
00:17:46 Let's make sure to properly spell it appointment data and pass it over right here.
00:17:53 And of course, we have to make sure that we call it within the scope.
00:17:56 So it needs to be within this if statement right here.
00:18:00 And as before, if this appointment exists, we'll reset the form by calling form.reset and then we'll do a router.push and we'll push to forward slash patients
00:18:15 forward slash user ID forward slash new dash appointment So same URL we're on right now, but this time forward slash success.
00:18:27 And to it, we can say question mark appointment ID is equal to the existing appointment ID.
00:18:37 Great.
00:18:38 Now we're so close to creating this appointment, but let's quickly check this validation.
00:18:44 It seems like you cannot get it from lib validation.
00:18:47 And that's because this schema is going to depend on whether we're trying to create, cancel, or schedule this.
00:18:54 So we can call the get appointment schema right here at the top, const appointment Form validation is equal to getAppointment to which we pass the type.
00:19:11 Okay.
00:19:11 So now this is good.
00:19:13 And it is complaining a bit about the appointment data.
00:19:16 Let's see why.
00:19:17 It says that the property reason is incompatible.
00:19:20 So we can add the exclamation mark at the end because we know that it'll be there.
00:19:26 And now we're good.
00:19:27 And we're so close to finally creating an appointment, but we cannot do it just And that's because if we go back to AppRight,
00:19:37 we have added all of these properties for the patient, but we haven't yet added them for the appointment.
00:19:44 So we have to create all of these attributes needed to make this work.
00:19:49 In this case, we'll need to create an attribute of relationship and this will be a one-way relationship with a patient.
00:19:58 We'll call it patient and it'll be a many-to-one relationship where appointment can contain one patient and patient can belong to many appointments and
00:20:08 when deleting a document, we can set to null.
00:20:11 So let's click create.
00:20:13 Let's also create a few other properties.
00:20:16 We'll use a date time property, quite an exciting one for the schedule.
00:20:21 Let's make it required.
00:20:23 Let's also add a reason of a type string.
00:20:28 Let's do 1000 characters and required.
00:20:31 We can also add a note.
00:20:34 Let's do 1000 characters required.
00:20:38 Or no, note might not be required.
00:20:40 So let's leave it empty or not required.
00:20:43 We need to have a primary physician, so primary physician.
00:20:48 Later on, you can make this a connection to the doctor's database.
00:20:52 That'll be of a type string 100 and required.
00:20:57 Let's also add an enum of status.
00:21:01 So that's going to be a status and different elements will be scheduled, pending, and canceled.
00:21:10 Let's also make it required.
00:21:14 We'll also need a user ID.
00:21:17 Let's make this 1000 characters and required.
00:21:21 And we'll also need a cancellation reason.
00:21:24 So cancellation reason.
00:21:28 That's going to be 1000 and not required.
00:21:33 Great.
00:21:34 I think we now have everything we need to create an appointment.
00:21:37 So let's go to our app, choose a doctor, choose a time, add a reason.
00:21:44 Let's say my head hurts.
00:21:49 I might have a migraine and let's click create appointment.
00:21:54 The button doesn't want to actually click.
00:21:57 So let's see why that is.
00:21:59 If I go here to the form, it's actually calling the on submit.
00:22:05 And the button should be of a type submit.
00:22:08 Yeah, it's a submit button.
00:22:10 So it must mean that we have gotten into the on submit, past the status, and we're looking if the type is create, which in this case should be,
00:22:23 and we're looking at the patient ID exists, which it should.
00:22:27 So I think we do get into this if statement right here, but we can do a console lock to verify here.
00:22:35 And we can also open up the console to see if anything is happening here.
00:22:39 No, not really.
00:22:41 Okay.
00:22:42 Next, let's see if we have successfully created an appointment by doing another console log and console logging the actual created appointment.
00:22:50 So back in here, I will click create appointment.
00:22:54 And it seems like nothing is happening in this appointment form.
00:22:58 Interesting.
00:22:59 It's like it doesn't get this type of create.
00:23:03 What about the page on the appointment?
00:23:05 Are we passing the type of create?
00:23:08 Yep, we are.
00:23:09 And we're also passing the patient ID.
00:23:11 So let's do one console log before we go into the if statement and console log the type and say before the type.
00:23:21 Or before the try, should I say.
00:23:23 So if we go back, click it once again and check the console in the browser, because that's where we'll see those actual events.
00:23:33 You can see that the app right exception error, we're missing a required parameter of database ID.
00:23:40 And this is most likely happening right here on the create appointment side of things, because it cannot get the database ID.
00:23:47 And there's only one reason why this could happen.
00:23:51 And that's because it cannot get it from the environment variables.
00:23:55 And why wouldn't it be able to get it from environment variables?
00:23:59 Well, that's because we're not adding the next public and it's trying to fetch it on the client side.
00:24:05 But why is it trying to fetch it on the client side if we're on the server?
00:24:09 Well, we're not considering that we forgot to specify the use server directive.
00:24:17 So now it will properly get access to all of these and hopefully create a new appointment.
00:24:23 Let's give it a shot by clicking create appointment one more time.
00:24:29 It's loading and it redirected us to success.
00:24:33 That is great.
00:24:35 Let's check out if the appointment has been added to the database.
00:24:40 If I go to appointments.
00:24:43 Yep.
00:24:43 There it is.
00:24:44 My head hurts.
00:24:45 I have a migraine.
00:24:46 That is great.
00:24:48 But I noticed one thing and that is that at the top, the appointment ID was undefined.
00:24:55 That's not good.
00:24:57 So let's see where we're navigating.
00:25:00 Appointment ID.
00:25:02 Oh, I think it was supposed to be a dollar sign ID right here.
00:25:06 Yep.
00:25:06 That's good.
00:25:07 Okay.
00:25:07 Not a big deal.