Build a Confirmation Dialog in React and Ant Design
In this lesson, we'll look to prepare the confirmation modal that gets displayed to the user when the users requests to make a booking.
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.
This lesson preview is part of the TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to TinyHouse: A Fullstack React Masterclass with TypeScript and GraphQL - Part Two with a single-time purchase.
[00:00 - 00:12] In this lesson, let's look to prepare the modal that gets displayed to the user when the request to book button has been selected in the listing page. We'll be using AntDesign's modal component to help facilitate this for us.
[00:13 - 00:36] For those who are unaware, modal dialogs are helpful since they often allow us to create a new floating layer over a certain page to either get user feedback or display information without having the need to interrupt a user's workflow. So let's create this modal within a component of its own that we'll call List ingCreateBookingModel.
[00:37 - 01:22] We'll prepare the components folder within the components folder in the listing module that is to contain an index file and we'll look to re-export this soon to be created component from the components index file. In this ListingCreateBookingModel, we'll import the React library, we'll also import the modal component from AntDesign and we'll export a component function we'll call called ListingCreateBookingModel.
[01:23 - 01:41] In the return statement, we'll want to display AntDesign's modal component and there's a few props we'll want to declare here to help prepare the modal the way we want it to. There exists a visible prop which receives a boolean value to help determine when the modal should be shown or not.
[01:42 - 01:52] True and the modal will show, false and the modal won't show. It will be helpful to have this property or value of this property kept as part of a component state.
[01:53 - 02:17] So we'll have the value for visible here be part of the component state in the Listing component that will be the parent of this component. So we'll assume a prop will be passed into this component called modalVisible which is to be a boolean and will be the value of the visible prop.
[02:18 - 02:41] The few other props values we'll look to declare will help have our modal be centered with the centered prop. We won't want to display a footer in the modal so we'll pass a value of null for this and the value of the onCancel prop is a callback that will trigger a function that we can use to close the modal.
[02:42 - 03:08] So we'll also assume that we'll have a function passed into this component that will call set modalVisible which will receive a boolean and return false and this function will control the value of the modalVisible prop. The onCancel callback function will trigger and call the set modalVisible function and it will pass in a value of false here.
[03:09 - 03:38] Let's look to have this component be rendered in the listing component. In the listing component will import listing create booking modal from the adjacent components folder and will create a new state property with a setter function that will help determine when this modal will be shown and will call this state property modalVisible and will initialize it with false.
[03:39 - 04:11] And we'll create a constant to represent the modal component. And we'll have this constant listing create booking modal elements be rendered in the component template.
[04:12 - 04:30] It shouldn't really matter where we render it in the template since it would automatically be placed in the center but will have it rendered outside of the row element. To have this modal be shown we'll need the modalVisible state property to be true.
[04:31 - 05:06] And we want the request to book button in the listing create booking component to facilitate this so we'll pass the setter function set modalVisible down to the listing create booking components. In the listing create booking component we'll specify the set modalVisible prop that it is to be passed down.
[05:07 - 05:23] And in the request to book button we'll add an on click prop which will trigger a callback and we'll call the set modalVisible function and pass a value of true. Let's now see what happens in our app.
[05:24 - 05:32] We'll pick some date picker values just to have our button be enabled. When we click the button the modal will be shown.
[05:33 - 05:48] The close icon will trigger the on cancel prop callback which we've stated will revert the modalVisible state value to false and have the modal be closed. Great.
[05:49 - 06:15] With the capability to open and close the modal let's now look to populate the contents of the modal that we'll expect to show to the user. In the listing create booking modal component file there's a few other components from antdesign we'll need to use like the button component, the divider, icon and typography.
[06:16 - 06:33] And we'll also destruct the paragraph text and title components from typography . There's also a few props we'll expect this component will receive that will help show the useful information in the actual modal.
[06:34 - 07:11] We'll want to receive the price of the listing per day which is to be a number and the check in date and check out dates selected by the user. Now these will be moment date objects so we'll import the moment interface from the moment library to define their shape.
[07:12 - 07:22] There's a small amount of data preparation we'll make. Between the check in and check out dates we'll be interested in getting the number of days that have been booked.
[07:23 - 07:37] With moment this is fairly straightforward and we can actually use the diff function from moment to get the difference between two moment dates and we can say we want it in days. This will give us the difference between the two days.
[07:38 - 07:52] If we recall we've mentioned we're interested in always counting the day being checked in as an additional day so we'll add one to this. The price value is the price of the listing per day.
[07:53 - 08:12] To determine the total price the user will pay based on the number of days booked we'll multiply the price per day with the days booked or the number of days that have been booked. We've also mentioned how us tiny house are interested in taking 5% of the total charge being made.
[08:13 - 08:35] We'll want to tell the user this as well so we'll have a constant to retrieve this value which will be 5% of the total listing price. And lastly the total price the user will pay will be a combination of the listing price which is the price per day multiply the days booked and the tiny house fee.
[08:36 - 09:27] Now we'll look to prepare the template of the modal component. [silence] The very beginning will display a title that will just show an icon of a key.
[09:28 - 09:58] We'll follow up with this with another title that says book your trip. We'll have a paragraph that says enter your payment information to book the listing from the dates between the date and the date.
[09:59 - 10:25] The date and date objects are in the moment format we want to be shown as strings here. To have the dates be displayed as strings we can use the moment format function and we can say we want to be shown in the format of month, 4 characters of the month, 2 characters for the day and 4 characters for the year.
[10:26 - 10:59] And we'll be placing these dates within text components that have the strong and mark props. [silence] We'll also import the moment function from the moment library with which we're using here.
[11:00 - 11:23] We'll place a divider after this div section. And then look to display information about the summary of the pricing the user will pay.
[11:24 - 11:49] And the first paragraph we'll have here, we'll want to tell the user the total listing price. So first we'll import the format listing price utility function we have in the libutals file in our client project.
[11:50 - 12:15] And we'll essentially want to tell the user that the price per day multiplied by the number of days booked will be equal to this total price that you would pay. And we'll use the format listing price function for the two different price values and we'll apply an argument or a value of the argument as false just so these values won 't be rounded up or down.
[12:16 - 12:41] We'll have another paragraph that highlights the tiny house fee which is 5% of the total listing price. So we'll have another paragraph we'll say tiny house fee we'll add a small subscript to illustrate that it's around 5% and then we'll display the price with the format listing price function.
[12:42 - 12:58] In this context we'll just not place the false value in the second argument since we'll probably want to have it in the rounded format. And we'll also have a paragraph element that attempts to show the total price.
[12:59 - 13:49] And one of the last things we'll do for now is we'll want to display the button that will be the confirmation button that actually makes the booking. So we'll place another defider and render the button and we'll make the button of type primary of size large and to have text that says book.
[13:50 - 14:00] The parent listing component let's ensure we pass the props that this modal component is to accept. The price will be the price of the listing.
[14:01 - 14:27] The values for the check-in date and checkout dates will come from the state properties in this listing component of the same name and we'll only want to pass these values for the price and check-in checkout dates when listing and these values exist. So we can place a Paternary statement and say that this component should only be shown when listing exists and the check-in and checkout date properties are defined.
[14:28 - 14:35] Otherwise this element constant will be null. Let's see how our modal will now look.
[14:36 - 14:46] We'll select some check-in and checkout dates. We'll select the ninth for check-in, the eleventh for checkout and when I click the request a book button I now see the information we've prepared.
[14:47 - 14:56] We see the icon up top, the title, book your trip. There's a description here that says into your payment information to book the listings from the dates between.
[14:57 - 15:12] So let's add maybe a character or a few a word between these two dates. So we'll go back to our create booking modal from the dates between this and checkout.
[15:13 - 15:42] So now if I go back and select maybe the same dates, ninth and eleventh, we'll add a space between and and December eleventh here for the checkout date. So now we get the description that says into your payment information to book the listing between these dates inclusive and here's the payments information that we expect the user is going to pay.
[15:43 - 15:50] There's the total listing price which is the listing price per day multiplied with a number of days being booked. The ninth, tenth and eleventh says three days.
[15:51 - 16:02] There's a tiny house fee charge and a total amount that's also being shown. For this total amount we could, there was a class we prepared to make this total section a little bit more large and bold.
[16:03 - 16:27] So we'll go back to our code and for this particular paragraph tag that talks about the total price, we'll add that certain class that we've created listing booking modal charge summary total. A slight mistake here, we're adding the class to the wrong paragraph section which is the listing pricing information.
[16:28 - 16:46] We'll copy that over and we actually want to add it in to the section that shows the total price. We'll save our changes, head back to our app, refresh the app, select some check in and check our dates and we'll see the total section now be presented the way we wanted to.
[16:47 - 16:51] Great. A few things to talk about here before we move forward.
[16:52 - 17:22] We've mentioned how for the listing price information we don't necessarily round the values here but we do so for the tiny house fee and total portions. Preferably it's probably more appropriate to have all the values shown to be a little bit more accurate and maybe show decimal values at least to two decimal places for all the number information but in this case we'll just keep the fee and total amount rounded up and down but you're more than welcome to change this as you please.
[17:23 - 17:40] The other thing to note, there's still a big piece missing in this modal and that's the actual section where the user is able to provide their payment information. And the next lesson we'll introduce this capability, there's probably one other thing we should talk about here.
[17:41 - 18:10] So we've noted over here that we have a tiny house fee and by illustrating this over here this sort of illustrates to the person making the booking that they're going to essentially pay this tiny house fee. If we take a look at our server code we notice that this is the actual create booking mutation resolver function that when we prepare the total price we simply multiply the listing price and the number of days in between check in and check out.
[18:11 - 18:26] And we simply take this total price value, pass it to our stripe charge function and this is the amount that the stripe charge is going to be made. And in the application fee we note that it's going to be 5% of whatever this amount is as the tiny house fee.
[18:27 - 18:55] If you look at the stripe documentation we'll link this in the lesson manuscript but there's a diagram that illustrates the flow of funds with fees in direct charges and it shows that when a payment is made the connected account is going to be paying the actual application fee and the connected account will be taking care of the stripe fees as well. So the way we currently have the setup on the client may not be fully accurate.
[18:56 - 19:19] So in this context this particular fee may not be what the person is paying. One way we can actually keep this the way it is is on the server the total amount could take into account that percentage and by doing so this application fee will simply remove that percent which makes this a little bit more accurate but we don't have this in the server currently.
[19:20 - 19:42] So at this moment in time it might make more sense to not show the tiny house fee on the client. So we'll remove that in that context we don't necessarily need this total price we just need the listing price the listing price available will scroll down we'll remove this tiny house fee portion and we'll just simply list the listing price.
[19:43 - 19:57] Head back to our client application launch the modal once again and we'll see the total value being shown here. In this context let's just have this in the non formatted state as well.
[19:58 - 20:19] So in the format listing price function will say false here go back to our app launch the modal again. If I'm seeing this correctly this makes a little bit more sense right now because in this context we simply tell the person making the payment this is the total amount that you're going to pay.
[20:20 - 20:51] Keep in mind we don't plan on sending this number value to the server on the server we simply recalculate that total price right here and we pass it to our stripe charge function and taking a better look at this diagram that application fee will simply be retrieved from the connected account. So the person making the payment just simply pays the total amount tiny house and stripe itself will simply pull in the amounts they want from the charge directed and where the nets amount will then be less.
[20:52 - 21:10] In the next coming lessons when we build out the mutation and conduct the mutation we'll start to look through our stripe connected account and see if the payments make the make sense and actually mimic what we are showing here and if there's any changes we need to make we'll make those changes as we move forward. Great job so far.