NextJS Templates
Meeting Room Booking App Tutorial with Back4App, Next.js and Vercel
23 min
in this tutorial, you will build bookit , a meeting room booking system using next js as the frontend framework and back4app as the backend service you will implement user authentication, room management, and booking functionality, and deploy the app on vercel 1\ prerequisites to complete this tutorial, you will need a back4app account (sign up at back4app https //www back4app com/ ) a back4app project (follow this guide https //www back4app com/docs/get started/welcome ) node js installed on your local machine ( installation guide https //nodejs org/ ) basic knowledge of javascript, next js, and rest apis (if needed, see javascript fundamentals https //www back4app com/docs/javascript guide ) 2\ setting up back4app log in to your back4app account and navigate to your project dashboard in the left sidebar, click database to access the data browser you will need to create the following classes to model the data 2 1 create the user class by default, parse handles user authentication, so no need to create this class manually parse automatically manages the following fields for you email email address for login password password (hashed) username optional username 2 2 create the room class in the data browser , click create a class , select custom , and name the class room add the following columns column name type description name string room name description string room description capacity number number of people the room can hold amenities array list of amenities (tv, wifi, etc ) price number price per hour image file image url owner pointer points to the user class 2 3 create the booking class create another custom class named booking add the following columns column name type description room pointer points to the room class user pointer points to the user class checkin date start date/time of the booking checkout date end date/time of the booking 3\ setting up next js and parse sdk create a new next js project npx create next app bookit app cd bookit app install parse js sdk npm install parse in the pages/ app js file, initialize parse with your back4app credentials import parse from 'parse'; parse initialize('your app id', 'your javascript key'); parse serverurl = 'https //parseapi back4app com'; function myapp({ component, pageprops }) { return \<component { pageprops} /> } export default myapp; replace 'your app id' and 'your javascript key' with your back4app app credentials 4\ implementing user authentication 4 1 user registration create a new page pages/signup js with a registration form import { usestate } from 'react'; import parse from 'parse'; export default function signup() { const \[email, setemail] = usestate(''); const \[password, setpassword] = usestate(''); const handlesignup = async (e) => { e preventdefault(); const user = new parse user(); user set('username', email); user set('email', email); user set('password', password); try { await user signup(); alert('signup successful!'); } catch (error) { alert('error ' + error message); } }; return ( \<form onsubmit={handlesignup}> \<input type="email" value={email} onchange={(e) => setemail(e target value)} placeholder="email" /> \<input type="password" value={password} onchange={(e) => setpassword(e target value)} placeholder="password" /> \<button type="submit">sign up\</button> \</form> ); } 4 2 user login create pages/login js for user login import { usestate } from 'react'; import parse from 'parse'; export default function login() { const \[email, setemail] = usestate(''); const \[password, setpassword] = usestate(''); const handlelogin = async (e) => { e preventdefault(); try { await parse user login(email, password); alert('login successful!'); } catch (error) { alert('error ' + error message); } }; return ( \<form onsubmit={handlelogin}> \<input type="email" value={email} onchange={(e) => setemail(e target value)} placeholder="email" /> \<input type="password" value={password} onchange={(e) => setpassword(e target value)} placeholder="password" /> \<button type="submit">login\</button> \</form> ); } 4 3 protected routes for protected routes, you can use next js api routes and check if the user is authenticated import parse from 'parse'; export default async function handler(req, res) { const user = parse user current(); if (!user) { return res status(401) json({ message 'unauthorized' }); } // proceed with the request } 5\ room management 5 1 displaying available rooms create pages/index js to list available rooms import { useeffect, usestate } from 'react'; import parse from 'parse'; export default function home() { const \[rooms, setrooms] = usestate(\[]); useeffect(() => { const fetchrooms = async () => { const room = parse object extend('room'); const query = new parse query(room); const results = await query find(); setrooms(results); }; fetchrooms(); }, \[]); return ( \<div> \<h1>available rooms\</h1> {rooms map(room => ( \<div key={room id}> \<h2>{room get('name')}\</h2> \<img src={room get('image') url()} alt={room get('name')} /> \<p>capacity {room get('capacity')}\</p> \<p>price ${room get('price')} per hour\</p> \</div> ))} \</div> ); } 5 2 adding a room create pages/add room js for adding new rooms (for authorized users) import { usestate } from 'react'; import parse from 'parse'; export default function addroom() { const \[name, setname] = usestate(''); const \[description, setdescription] = usestate(''); const \[capacity, setcapacity] = usestate(0); const \[price, setprice] = usestate(0); const handleaddroom = async (e) => { e preventdefault(); const room = parse object extend('room'); const room = new room(); room set('name', name); room set('description', description); room set('capacity', capacity); room set('price', price); try { await room save(); alert('room added successfully!'); } catch (error) { alert('error ' + error message); } }; return ( \<form onsubmit={handleaddroom}> \<input type="text" value={name} onchange={(e) => setname(e target value)} placeholder="room name" /> \<textarea value={description} onchange={(e) => setdescription(e target value)} placeholder="description">\</textarea> \<input type="number" value={capacity} onchange={(e) => setcapacity(parseint(e target value))} placeholder="capacity" /> \<input type="number" value={price} onchange={(e) => setprice(parseint(e target value))} placeholder="price" /> \<button type="submit">add room\</button> \</form> ); } 5 3 room details create pages/rooms/\[id] js to view detailed information about a room import { userouter } from 'next/router'; import { useeffect, usestate } from 'react'; import parse from 'parse'; export default function roomdetails() { const router = userouter(); const { id } = router query; const \[room, setroom] = usestate(null); useeffect(() => { if (!id) return; const fetchroom = async () => { const room = parse object extend('room'); const query = new parse query(room); query equalto('objectid', id); const result = await query first(); setroom(result); }; fetchroom(); }, \[id]); if (!room) return \<div>loading \</div>; return ( \<div> \<h1>{room get('name')}\</h1> \<img src={room get('image') url()} alt={room get('name')} /> \<p>{room get('description')}\</p> \<p>capacity {room get('capacity')}\</p> \<p>price ${room get('price')} per hour\</p> \</div> ); } 6\ booking system 6 1 booking a room add booking functionality in pages/rooms/\[id] js by adding a booking form const \[checkin, setcheckin] = usestate(''); const \[checkout, setcheckout] = usestate(''); const handlebooking = async () => { const booking = parse object extend('booking'); const booking = new booking(); booking set('room', room); booking set('user', parse user current()); booking set('checkin', new date(checkin)); booking set('checkout', new date(checkout)); // check for double booking (example logic) const query = new parse query(booking); query equalto('room', room); query greaterthanorequalto('checkin', new date(checkin)); query lessthanorequalto('checkout', new date(checkout)); const overlap = await query first(); if (!overlap) { try { await booking save(); alert('booking successful!'); } catch (error) { alert('error ' + error message); } } else { alert('room is already booked for the selected time range '); } }; 6 2 viewing and canceling bookings create pages/my bookings js to view and cancel bookings import { useeffect, usestate } from 'react'; import parse from 'parse'; export default function mybookings() { const \[bookings, setbookings] = usestate(\[]); useeffect(() => { const fetchbookings = async () => { const booking = parse object extend('booking'); const query = new parse query(booking); query equalto('user', parse user current()); const results = await query find(); setbookings(results); }; fetchbookings(); }, \[]); const handlecancel = async (id) => { const booking = bookings find(b => b id === id); if (booking) { await booking destroy(); setbookings(bookings filter(b => b id !== id)); } }; return ( \<div> \<h1>my bookings\</h1> {bookings map(booking => ( \<div key={booking id}> \<p>room {booking get('room') get('name')}\</p> \<p>check in {new date(booking get('checkin')) tolocalestring()}\</p> \<p>check out {new date(booking get('checkout')) tolocalestring()}\</p> \<button onclick={() => handlecancel(booking id)}>cancel booking\</button> \</div> ))} \</div> ); } 7\ deploying to vercel install the vercel cli npm install g vercel deploy your next js app with vercel follow the prompts to deploy your app to vercel once deployed, your app will be live on a public url 8\ conclusion in this tutorial, you built a bookit app with next js for the frontend and back4app as the backend you implemented user authentication, room management, and booking functionality finally, you deployed the app on vercel you can now expand the app with additional features like search, payment integration, or notifications