AirBnB clone with NextJS 14 -Part 2

14 min readOct 29, 2024

In this post we are going to complete the NextJS 14 AirBnB clone, which we started in part-1.

This post have been inspired by the awesome YouTube video by Traversy Media. You can find the link here.

Here, first we will write the code to add room. So, create a new action in createRoom.js file. It is similar to earlier actions. Here, we are first importing the required things.

Then inside the function createRoom, we are first getting the databases from the createAdminClient. Nexy, in the try block we are getting the user from checkAuth. After that we are using databases.createDocument().

Here, we are passing the database and collection name from environment file and also ID. Next, we are passing an object with user id and other data required in room.

We are returning success at the end of try block. In case of error we are returning error. in catch block.

Next, we will create an add folder inside rooms folder and page.jsx inside it.Here, we are importing the required things including useFormState and also createRoom created earlier.

Inside the AddRoomPage component, we have used the useFormState and passed the createRoom. After that used the router and useEffect. Inside the useEffect, if their is an error we are showing in a toast. In the case of success we are showing a toast and pushing to home route.

In the return we have a Heading and then a form containing name, description and sqft.

In the same file, we are also adding input for capacity, price per person, address, location, availability, amenities, image and finally a submit button.

Now, click on Add room or go to http://localhost:3000/rooms/add and fill the required fields.

After that click on the Save button.

Now, you will see a new room is created but the image is missing.

For showing the image we will go back to appwrite and click on Storage and then Create bucket button.

In the pop-up we are given it a Name and Bucket ID. Both are rooms in our case.

We also need to give access to it. So, go to Settings and then Permissions. After that for role click on Any.

For Role we have given READ permissions. Now, click on Add role and then All users.

For Users give all permissions and click on Update button.

Now, go back to createRoom.js file. Here, we need to add the upload image logic. Here, we have first added storage in createAdminClient. Next created a variable imageID.

Then in formData getting the image. Then ina if statement checking if the image is there and other parameters. Then in a try block inside the if we will store the image in appwrite using createFile function. And we are assigning the response to imageID.

We are catching the error in a catch block and returning the error. Also, in ther else we are console logging for further error. We are also passing the image in the createDocument().

Again go back to http://localhost:3000/rooms/add and this time add an image before clicking the Save button.

Again we have no image in http://localhost:3000/

But going back to appwrite, we will see the image.

We will add the logic to show image in home page and also Single page. But first we are adding a no-image.jpg file inside public -> images folder. This is if user doesn’t upload a image as it’s not required field.

Now, in the RoomCard.jsx file, we are getting the bucketId and projectId from environment file. After that the imageUrl from the appwrite link passing bucketId and projectId.

Then we have an imageSrc variable in which we are checking if room.image is their, then use the imageUrl or else will take the no-image.jpg. Inside the return we are now passing imageSrc in src of Image.

Now, we show image from external source like appwrite in NextJS, we need to update the next.config.mjs file.

Now, we will see the No Image and an image in the newly created rooms in http://localhost:3000/

Now, the old rooms won’t work fine. So, in appwrite, we will select them and click on Delete button.

Next, we will get a pop-up for confirmation of Delete.

Back in http://localhost:3000/ we will see only the new rooms.

Now, we need to show the image in Single page also. So, we need to update the rooms -> [id] -> page.jsx file which have the RoomPage component.

Here, we are adding the same code which we added earlier for RoomCard.jsx file.

Now, if we click on the View Room for room with an image we will see the image.

Also, click on the View Room for room with no image we will see the No photo image.

Now, we will create logic to show rooms of the logged in user. So, we will create an action file getMyRooms.js inside actions folder.

This is similar to earlier actions and here we are first getting the logged in user details from cookies. Then in the try block, we are getting the account and databases details from createSessionClient().

Then we are getting the userId and then the rooms associated with it. And we are returning the rooms. In the catch block, we are redirect to error.

Next, create a new component called MyRoomCard.jsx inside the components folder. Here, we will get the room props and show the name and the link to take to that room.

Now, we will create a my folder inside the rooms folder. Inside it we will create the usual page.jsx file. This will use getMyRooms() created earlier to get all the rooms.

After that inside the return statement, we are looping through the rooms and sending each room to MyRoomCard component, created previously.

Now, click on My Rooms or go to http://localhost:3000/rooms/my and we will see all rooms associated with the user.

Now, Sign Out and login with other user.

Now, click on My Rooms or go to http://localhost:3000/rooms/my and we will see no rooms for this user.

Now, we will create a new room for this user by going to http://localhost:3000/rooms/add or clicking on Add Room.

Now, click on My Rooms and we will see the newly created room for the user.

Now, we will add the logic to delete a room. So, create a new action called deleteRoom.js inside the actions folder. It is similar to the previous action.

Here, after getting the rooms for the user, we are getting that particular room by the passed in roomId. After that in a if statement, we are using another appwrite function of deleteDocument() to delete the room.

After that returning success and in case of error returning error.

Next, inside the components folder create DeleteRoomButton.jsx file. Here, we have a button inside the return, which is calling an handleDelete function.

Now, the handleDelete function is first having a confirmation pop-up. After that using deleteRoom() created earlier we are deleting the room and showing a toast message. In case of failure also, we re showing a toast message.

Now, we will add this DeleteRoomButton in the MyRoomCard.jsx file. Here, we are passing the roomId of the room.

Now, in http://localhost:3000/ we will remove a room which have an inappropriate title.

Next, click on My Rooms and click on the Delete button for the room.

It will show a confirmation pop-up. Here, click on the OK button.

We will get a success toast of Room deleted successfully!.

Now, we want to create the booking logic. So, go to https://cloud.appwrite.io and click on Databases. Then click on Create collection button.

A pop-up will be opened and here give the collection the name of bookings and ID of bookings.

Next, click on the Attributes tab and after that Create attribute button. A drop-down will open and here click on String.

Give the Attribute key as user_id and other fields. Then click on Create button.

Again click on Create attribute button and scroll down and click on Relationship.

In the pop-up select One-way relationship. The Attribute key as room_id and Relation as Many to one. Also, select Cascade for On deleting a document.

For the new attribute select Datetime in Create attribute dropdown.

Now, give the Attribute key as check_in and make it required.

We have also created and attribute called check_out which is of type Datetime

Now, go to Settings tab for bookings.

Scroll a bit down to go to Permissions and here click on + and then click on All users.

Here, we have selected all permissions and then click on Update button.

Now, in the page.jsx file of rooms -> [id] send the room as a props in BookingForm.

Now, we will create a new action of bookRoom.js inside actions folder. It is similar to earlier actions, but inside the try block we are getting different date and time for check in and check out.

After that we are creating a booking with the createDocument function and passing bookingData. We are returning success as true or error in case of error.

Next, we will link the BookingForm.jsx file with this action. After making it a client component and adding the necessary imports, we are adding useFormState and router.

Inside the useEffect we are sending the success or the error toast. Inside the return we will add action and also a value for room_id input.

Now, go to a room and book a room.

We will get the toast of Room has been booked.

Also, going to https://cloud.appwrite.io will show the room is been booked in bookings collection.

Now, we will add the logic to show something when a room is been booked. So, create getMyBookings.js inside actions folder.

It is similar to earlier action files. Here, we are first getting the user and through the user id, getting all his bookings. We are returning bookings in case of success. Or returning error in case of failure.

Next, create a component called BookedRoomCard.jsx inside the components folder. Here, we are showing the room name and the check in and check out time. To convert the time to correct format we are using a formatDate function.

Now, inside the app folder, create a bookings folder. And a page.jsx file in it. This file is taking the bookings array from getMyBookings action and looping through it. After that it is passing each booking to BookedRoomCard component.

Now, click on the Bookings or go to http://localhost:3000/bookings and we will see the booking.

Next, we will create the logic to delete a booking. So, create a file cancelBooking.js inside actions folder.

Here, we are getting a bookingId in props. We are getting the user from the session. First we are getting the user and the booking. Also, checking if the booking belongs to the current user.

We are finally deleting the booking from the database using deleteDocument() of appwrite. Returning a success true if it’s done or an error if some issue.

Now, create a file CancelBookingButton.jsx inside components folder. Here, we have a button inside the return which calls handleCancelClick function.

The handleCancelClick() after taking the confirmation calls the cancelBooking action created earlier and passes the bookingId.

Now, we will add the CancelBookingButton component in BookedRoomCard.jsx file and pass the booking id.

Now, click on Bookings or go to http://localhost:3000/bookings and click on the new Cancel Booking button.

A pop-up will come for the confirmation. Here, click on OK.

We will be redirected to http://localhost:3000/bookings and the booking will be cancelled.

Now, we will write the logic to check if a room is available for booking. We cannot allow multiple booking at the same time. So, create an action checkRoomAvailability.js inside actions folder.

Here, we are getting roomId, checkIn and checkOut in props. We are using a function toUTCDateTime() to convert the checkIn and checkOut. Here, we are using a luxon library.

After that we are fetching all bookings for the room. Next, we are looping through the bookings array and checking for an overlap. We are using the dateRangesOverlap() to check the overlap.

We are returning false in case of overlap or returning true.

Since, we are using a luxon library, we need to install it through terminal.

Now, we will add the checkRoomAvailability in the bookRoom.js file. Here, before the bookingData, we are checking if the room is available by passing all data in checkRoomAvailability(). If we are getting false, we are returning error.

Now, click on a room and give a Check in and check out date and time and click on Book Room.

The room is booked. Note the time is from 9:30 PM to 10:30 PM on Oct 29.

Now, we will again book the same room but the Check in time is Oct 29 10:25 PM, which is overlapping with earlier booking.

We are getting a toast error This room is already booked for the selected time.

We have changed the Check in time is Oct 29 10:35 PM and we are able to book the room.

We have deployed the app in vercel and we are still not able to book overlapping time.

But a different time we are able to book. Here, we have booked the room for a different user.

This completes our AirBnB clone. You can find the complete code here.

--

--

Nabendu Biswas
Nabendu Biswas

Written by Nabendu Biswas

Architect, ReactJS & Ecosystem Expert, Youtuber, Blogger

No responses yet