Select Day
Creating the "Choose Date" Page
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
Lesson Transcript
[00:00 - 00:08] So the next thing we're going to look into is the choose time page. So this is pretty much at the core of our little product here.
[00:09 - 00:18] So it's going to be the page where the user will select which time slot they want to book. And you might be tempted to reach for some calendar component on NPM for this.
[00:19 - 00:26] And I'm sure there are hundreds or thousands of them, but it's actually quite a simple problem. So let's just try and solve it ourselves.
[00:27 - 00:33] We will be using a date utility library though. And please don't reach for a moment if you've been using that before.
[00:34 - 00:40] It's outdated and it was never using immutable. So it's annoying to work with.
[00:41 - 00:49] Just please go for something else. I'm using DateFNS, which I've been using for a number of products and that works perfectly fine.
[00:50 - 01:04] They are working on a proposal for JS called Temporal, which maybe will mean that we won't need a library whatsoever in the future, but that isn't just ready yet. So let's use DateFNS and try to create a little page.
[01:05 - 01:22] I will first add DateFNS here. And then we will create a new file for the choose Date page, TSX.
[01:23 - 01:36] Let me just paste that in here because I've written it beforehand. So what we have here is similar to before, we get the onProceed function from our context.
[01:37 - 01:44] Now we also get the onGoBack. Whoops, I moved the shared components.
[01:45 - 01:58] Let me just do this. We will also have an onGoBack now because this is not the first page, so the user should be able to go back and change their service type or description.
[01:59 - 02:12] Then we have a little state that says which month are we in and we'll just create a new date, so that will default to current time. And then we'll get the start of month that DateFNS offers.
[02:13 - 02:22] So that will give us the first minute of this month. And then we'll add a month to get the preceding month.
[02:23 - 02:38] Then we'll just show, please select the date and we will show one month component for this month and one for the next month. And right now, all the one month component does is that it shows this month formatted as month name and then year.
[02:39 - 02:51] And then below that we'll have our primary button for proceeding and then we'll have a secondary button to go back. So we've created a little flex row here with justify between which will make those go out to either side.
[02:52 - 03:04] Let's try and use this in our booking instead of this placeholder. So I will import that.
[03:05 - 03:25] And if we go here now and go to the next page, we can see now that it says August 2023, which is the time of recording this, next month is going to be September 2023. If we click the go back button, we go back to the previous page and if we click proceed, we get to the enter email page.
[03:26 - 03:40] Now there we are actually stuck because there's no going back or forth from here. So in order to turn the one month placeholder into an actual component, let's just quickly think about what a calendar actually looks like.
[03:41 - 03:51] I expect the calendar that shows a month to be divided into weeks. And I'm Danish and in Denmark, a week starts on Monday, but I know that it's different in the US and other places.
[03:52 - 04:01] But when I see a calendar, I will expect Mondays to be the left most column in a grid. And then I'll be expecting each row to represent one week.
[04:02 - 04:09] Now there can maximum be 31 days in one month. And that gives us a set of rows of four and a half rows.
[04:10 - 04:24] But we might need to show the last bit of the previous month on the first row and maybe the first bit of the next month on the last row. So in total, we should have six rows because that is the maximum number that we will ever need.
[04:25 - 04:36] So we will create an array of 42 days and turn those into a grid. Let's create an actual component for the one month.
[04:37 - 04:44] I'll create a new file here called one month. .tsx and paste this code in here.
[04:45 - 04:50] And let me quickly go over this. So like I said, we're creating an array that has 42 items in it.
[04:51 - 04:56] And this is a weird shortcut way to do that. We're then mapping over each of these items.
[04:57 - 05:07] And for each of them, we're ignoring the actual value because that's going to be undefined, but we want the index. And so we're going to add i to whatever is the day.
[05:08 - 05:15] So month is already the start of whichever month we're showing here. That's how we were using it in our outer component.
[05:16 - 05:21] And then we will subtract. So as I said, I want Monday to be the first day in the calendar.
[05:22 - 05:37] And this get day, even though IntelliSense here says it's using local time, this will actually return zero for Sunday. So what I do is I subtract one, and then I use the modules operator to wrap it around the week, so to speak.
[05:38 - 05:43] So this is just a way to make Monday the first day of the week. If you don't want that, then don't do this.
[05:44 - 06:09] But in order to do this, or the what we get from this is that we make sure that we start the grid with the preceding month, whichever days we need from that to get the first week in the current month represented as well. We then create a little flex box here that first has a little bit of a header, and that will just show the month and the year.
[06:10 - 06:19] And then after that comes a grid. And so you can see I specify that it will have seven columns and six rows, and then we will have a gap of 1.5.
[06:20 - 06:27] And that was just what I found looked nice. And then we map over each of these items in our array, which is now an array of dates.
[06:28 - 06:44] And then we can call this, this is also from DateFNS. So is same month, if this is not in the current month, so this day that we're looking at right now, if it's either from the previous month or the next month, then we don't want it to appear in our calendar.
[06:45 - 06:59] But in order for the grid to work, there still needs to be a div. So what I do is simply I insert an empty div that has this key, so it will be a diffed correctly by React, but it doesn't actually show anything.
[07:00 - 07:08] If this isn't true, then we will be returning a day component, and that says the day to whichever day we're looking at. So let's take a look at that.
[07:09 - 07:17] That's defined right up here. So Date just takes a date, and it will just look a little bit at the current, at the day that we're looking at.
[07:18 - 07:24] So we will figure out, is this today? Is it in the past, or is it perhaps on a weekend?
[07:25 - 07:35] And then it will say, well, disabled means that if it's in the past or if it's a weekend, then we probably don't want people to be able to select this. So we're going to gray out these particular days.
[07:36 - 07:44] And so we're using CLSX to figure out which classes it should be. So we make it H10 and W10, so height of 10.
[07:45 - 07:56] I don't get IntelliSense here because this is not in, if I had it in here, I would get IntelliSense, but height 10 and W10 is 40 pixels wide and tall. So little squares.
[07:57 - 08:04] And then I make it a flexbox just so that I can center the text inside of it nicely. I also transition the colors.
[08:05 - 08:12] We'll be getting back to that afterwards. So we won't see that right now, but it's going to make sense a little bit later on.
[08:13 - 08:31] And then what the day is, actually, it's a button, and it's a disabled button. If we disabled it using this logic up here, and then it has this class, and then it just formats the date with a single D. So this is data FNS syntax for just showing the date number in the month.
[08:32 - 08:42] And let's try and use that in this page instead of our placeholder here. So now we should be able to import it.
[08:43 - 08:46] There we go. And we can get rid of this as well.
[08:47 - 08:51] And let's try and take a look at what that looks like now. All right.
[08:52 - 08:59] So we have two one month components. And now instead of just telling us which month they are, we will see the header like we specified.
[09:00 - 09:07] And then you can see here we have these days that are past or weekend. So today is the 18th.
[09:08 - 09:15] So all of these days are grayed out because they're in the past. There is one day in the previous month that isn't shown here.
[09:16 - 09:23] So that is just an empty div. And we likewise have three empty divs here and probably another row of them down here.
[09:24 - 09:35] So those are not doing anything, but because they belong to the next month and we don't care about that. And the same goes for September.
[09:36 - 09:43] So this is starting to look like our design, but there are a few things missing still. First of all, the users should be able to go back and forth through the months.
[09:44 - 09:50] So we need little buttons with arrows on them at the top. We also want to show if a date is available.
[09:51 - 10:01] That is if there are any times available on a specific day and then the users should be able to select the day. But for the back and forth buttons, let first install some icons.
[10:02 - 10:10] So the people who made tailwind CSS have created a set of icons called hero icons. You can go to heroicons.com to take a look at them.
[10:11 - 10:14] They're free and they're very nice. So let's just add those.
[10:15 - 10:29] So I'll install the react package like so. And then allow me to just paste in everything here because there are a few changes that we're going to be making.
[10:30 - 10:37] So I'm importing here chevron left and right from this hero icons package. And down here, you can see things have changed a bit and I'll go back to that.
[10:38 - 10:55] First of all, I've added little buttons on top of the calendar. If there's a go to previous month call back specified, we will show a button on the left that has the chevron left icon and it will call the go to previous month.
[10:56 - 11:02] And similar for next month on the right. But there are a few other things that we've added to the one month.
[11:03 - 11:12] So the calendar props now has this availability map. And what that is, is basically a map that maps a day to a Boolean value.
[11:13 - 11:24] And since we can't use dates as keys in a map, we're using the stringified value of a date. But that basically specifies whether or not a certain date is available.
[11:25 - 11:30] And you can see that it's optional. And the reason that I'm doing this is to allow this to also be in a loading state.
[11:31 - 11:40] And this is just a way to short circuit that. So if it is undefined entirely, then that means that it is currently loading the availability map.
[11:41 - 11:49] We don't have back end for this yet, so we're not going to be using it just yet . But I just wanted to finish this one month component for now.
[11:50 - 12:03] We're then adding something called selected day that also there's a callback that we can call to change this selected day. And then we have these two callbacks for going back and forth through the months.
[12:04 - 12:14] So these values are mostly being passed on to the day component. And that, as you can see, has also added quite a few extra properties.
[12:15 - 12:22] So this can now reveal whether or not it's loading. So if the availability map is undefined, then it's loading.
[12:23 - 12:42] However, if it is defined, then we will specify that this day is available if this map contains this or if the map, given this certain day, is true. And you can see here I'm formatting the date so that it's a string so that this will always work.
[12:43 - 13:07] I then add the on select and is selected to check if this is the same day as the selected day, then is selected will be true and on select will pass on to the select that was passed up here. The day then also takes some properties specifically it takes the loading state , the available state, and then on select and is selected.
[13:08 - 13:14] And we're using those. And mostly what I'm doing with that is that I'm adding some logic here to the class name.
[13:15 - 13:30] So I'm giving this a red border if the day is today, unless it's selected because if it's selected and it should have the indigo border. And then we then specify that the day is going to be green or yellow based on the availability.
[13:31 - 13:44] So as soon as the availability map is available, then the day will be either green or yellow if it's not disabled. We then finally add the on click handler here to make everything go through.
[13:45 - 13:55] All right, so let's try and use this updated one month in our choose date page. And let me just you can see here that these two now missing some properties.
[13:56 - 14:14] Let me just paste some things in here as well to make sure I'm not missing anything. So this is the updated choose date component.
[14:15 - 14:30] So it has a selected day and a set selected day, which can be undefined, but otherwise it's a date. Go to previous and next month, which just add either negative one month or positive one month to this month.
[14:31 - 14:36] And then the availability map, which is currently just this object. So it's always defined.
[14:37 - 14:44] So that means we're not setting this to the loaded state or anything. We're just going to say currently right now there's no availability.
[14:45 - 14:51] Every day is unavailable. So we then update these two month components here.
[14:52 - 15:00] So the left one will have go to previous month set, but not go to next month. And the one on the right will have go to next month set.
[15:01 - 15:09] So this will show the little button on the right and this will show the little ball on the left. And then they both get the rest of these.
[15:10 - 15:25] Let's try and take a look at what this looks like now. If I can spell.
[15:26 - 15:31] And you can see a few updates here now. So first of all, don't be confused that it is no longer the 18th, I think it was.
[15:32 - 15:38] I had to reshoot this video. So it's now the 28th, but everything else should be the same.
[15:39 - 15:48] So you can now see there's a little button here and there. And we have a red outline for today, which is the 28th at the moment.
[15:49 - 16:00] So if I click on the 29th, that gets an indigo button border. If I click on the 28th, which is today, then the selection will override the fact that it is today.
[16:01 - 16:06] And let's try and see if these actually work. It looks like I can go back and forth through the months as well.
[16:07 - 16:28] And you can see the selected day will follow. [ Silence ]
This lesson preview is part of the Fullstack Typescript with TailwindCSS and tRPC Using Modern Features of PostgreSQL course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack Typescript with TailwindCSS and tRPC Using Modern Features of PostgreSQL, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
![Thumbnail for the \newline course Fullstack Typescript with TailwindCSS and tRPC Using Modern Features of PostgreSQL](/_next/image?url=https%3A%2F%2Fs3.amazonaws.com%2Fassets.fullstack.io%2Fn%2F20240619184857865_KristianDupont_FullstackTypeScriptwithTailwindCSSandtRPCusingModernFeaturesofPostgreSQL_1450.67x816_CoverImage%2520%25281%2529.png&w=3840&q=75)