













































Preview text:
  lOMoARcPSD| 36625228   TRƯỜNG ĐẠI HỌC 
SƯ PHẠM KỸ THUẬT THÀNH PHỐ HỒ CHÍ MINH      ---- ---- 
HCMC University of Technology and Education  KHOA CÔNG NGHỆ THÔNG TIN 
NGÀNH CÔNG NGHỆ THÔNG TIN  BÁO CÁO ĐỒ ÁN 
CÔNG NGHỆ PHẦN MỀM MỚI  BOOKING APP MERN STACK 
GVHD: ThS. Nguyễn Minh Đạo 
 Sinh viên thực hiện:  Phan Thái Bảo  20110071    
Thành phố Hồ Chí Minh, tháng 12 năm 2023        lOMoARcPSD| 36625228 Mục lục 
Chương 1: Tổng quan chương trình ................................................................................ 1 
1.1. Giới thiệu về chương trình: ............................................................................... 1 
1.2. Các yêu cầu chức năng: ..................................................................................... 1 
1.3. Các yêu cầu phi chức năng ................................................................................ 1 
Chương 2. Nội dung..................................................................................................... 2 
2.1. Database: ........................................................................................................... 2 
2.1.1 Class diagram .................................................................................................. 2 
2.1.2 Lược đồ Use Case ........................................................................................... 2 
2.1.3 Models ............................................................................................................ 2 
2.1.4 Tóm tắt database ............................................................................................. 3 
2.2. Backend: ........................................................................................................... 4 
2.2.1 Register ........................................................................................................... 4 
2.2.2 Login ............................................................................................................... 4 
2.2.3 Get profile ....................................................................................................... 5 
2.2.4 Log out ............................................................................................................ 5 
2.2.5 Upload ảnh bằng link ...................................................................................... 5 
2.2.6 Upload ảnh từ máy .......................................................................................... 6 
2.2.7 Tạo place ......................................................................................................... 6 
2.2.8 Get place của user ........................................................................................... 7 
2.2.9 Get place by id ................................................................................................ 7 
2.2.10 Chỉnh sửa nơi ở ............................................................................................. 7 
2.2.11 Get place ....................................................................................................... 8 
2.2.12 Đặt chỗ .......................................................................................................... 8 
2.2.13 Get booking ................................................................................................... 8 
2.2.14 Hủy booking .................................................................................................. 9 
2.3. FrontEnd ........................................................................................................... 9 
2.3.1. Giao diện Trang chủ: ...................................................................................... 9 
2.3.2 Giao diện trang Đăng nhập ........................................................................... 10 
2.3.3 Giao diện trang đăng ký ................................................................................ 11 
2.3.4 Giao diện trang Tài khoản ............................................................................. 12 
2.3.5 Giao diện trang chi tiết nơi ở ......................................................................... 14 
2.3.6 Giao diện trang Booking ............................................................................... 16 
2.3.7 Giao diện trang My Booking ......................................................................... 18 
2.3.8 Giao diện trang My accommodations ............................................................... 19 
2.3.9 Giao diện trang thêm nơi ở mới ........................................................................ 20   
Chương 3. Cài đặt và kiểm thử.......................................................................................23 
3.1. Cài đặt:...................................................................................23 
3.1.1 Back end:...........................................................................23 3.1.2 Front 
end:...........................................................................23      lOMoARcPSD| 36625228
3.2. Demo chương trình....................................................................24 
Chương 4. Kết Luận.........................................................................................................42 
41. Kết Luận:.................................................................................42 4.2. Hướng phát 
triển.......................................................................42      lOMoARcPSD| 36625228
Chương 1: Tổng quan chương trình 
1.1. Giới thiệu về chương trình: 
Booking app Airbnb là một nơi giúp chúng ta có thể đặt được những chỗ 
yêu thích ở những nơi mà chúng ta muốn đến. Chúng ta có thể lựa chọn 
được những nơi ở có giá vừa phải, có thời gian check in, check out và có 
giới hạn số người khi ở. Bên cạnh đó nó còn cho phép chúng ta có thể chia 
sẻ chỗ ở của mình đến với mọi người 
1.2. Các yêu cầu chức năng: 
- Người dùng có thể tạo tài khoản với các thông tin cơ bản, đăng nhập vào 
hệ thống để có thể tiến hành lựa chọn, đặt chỗ hoặc chia sẽ chỗ ở của  mình 
- Người dùng có thể xem chi tiết nơi ở và tiến hành đặt chỗ 
- Người dùng có thể xem lại chi tiết đơn đã đặt hoặc hủy đơn 
- Người dùng có thể chia sẽ nơi ở của mình 
- Người dùng có thể xem và chỉnh sửa nơi ở đã chia sẽ 
1.3. Các yêu cầu phi chức năng 
- Hệ thống đảm bảo tính dễ sử dụng cho người dùng 
- Thông tin mô tả, hình ảnh nơi ở đúng với thực tế 
- Website dễ sử dụng cho các nền tảng khác nhau (desktop, mobile,  tablet…)      lOMoARcPSD| 36625228 Chương 2. Nội dung  2.1. Database:  2.1.1 Class diagram   
2.1.2 Lược đồ Use Case    2.1.3 Models  - User model:      lOMoARcPSD| 36625228
const UserSchema = new Schema({  name: String, 
 email: {type:String, unique:true},  password: String, }); 
Tạo bảng User với với các trường như name, email, password  - Booking model 
const bookingSchema = new mongoose.Schema({ 
 place: {type:mongoose.Schema.Types.ObjectId, required:true, ref:'Place'}, 
user: {type:mongoose.Schema.Types.ObjectId, required:true}, 
 checkIn: {type:Date, required:true}, checkOut: {type:Date, required:true}, 
name: {type:String, required:true}, phone: {type:String, required:true}, price:  Number, }); 
Tạo bảng booking với các trường như place (khóa ngoại đến bảng 
Place), user (khóa ngoại đến bảng User), checkIn, checkout, name, phone,  price.  - Place model 
const placeSchema = new mongoose.Schema({ owner: 
{type:mongoose.Schema.Types.ObjectId, ref:'User'}, title: 
String, address: String, photos: [String], description: 
String, perks: [String], extraInfo: String,   checkIn: Number,  checkOut: Number,  maxGuests: Number,  price: Number, }); 
Tạo bảng Place với các trường như owner (khóa ngoại đến bảng User), 
title, address, photos, description, perks, extraInfo, checkIn, checkout,  maxGuests, price 
2.1.4 Tóm tắt database 
Đây là một hệ thống dùng để đặt chỗ ở. Người dùng có thể xem thông 
tin phòng, đặt chỗ, hủy chỗ đã đặt đồng thời người dùng cũng có thể chia sẽ 
nơi ở của mình đến người khác và có thể chỉnh sửa chỗ ở đã chia sẽ. 
Mỗi người dùng có thể đặt nhiều chỗ , những mỗi chỗ đặt chỉ thuộc về 
một người dùng (1 – N) 
Mỗi nơi ở có thể có nhiều lượt đặt chỗ và mỗi lượt đặt chỗ chỉ thuộc về  một nơi (1 – N) 
Mỗi người dùng có thể đặt nhiều nơi và mỗi nơi có thể được đặt bởi 
nhiều người dùng (N – N)      lOMoARcPSD| 36625228 2.2. Backend:  2.2.1 Register 
app.post('/api/register', async (req,res) => { 
 mongoose.connect(process.env.MONGO_URL); 
const {name,email,password} = req.body;   try { 
 const userDoc = await User.create({  name, email, 
 password:bcrypt.hashSync(password, bcryptSalt),   });   res.json(userDoc);   } catch (e) {   res.status(422).json(e);  }  }); 
Tiến hành tạo mới user với name, email, password từ request gửi đến 
(password được mã hóa) sau đó trả về thông tin user được tạo. Nếu lỗi trả về 
lỗi 422 và thông tin lỗi  2.2.2 Login 
app.post('/api/login', async (req,res) => { 
mongoose.connect(process.env.MONGO_URL); 
const {email,password} = req.body; const 
userDoc = await User.findOne({email}); if  (userDoc) { 
 const passOk = bcrypt.compareSync(password, userDoc.password);  if (passOk) { jwt.sign({   email:userDoc.email,  id:userDoc._id 
 }, jwtSecret, {}, (err,token) => {   if (err) throw err; 
 res.cookie('token', token).json(userDoc);   });   } else { 
 res.status(422).json('pass not ok');   }   } else {   res.json('not found');   }  }); 
Đầu tiên sẽ dùng findOne để tìm email trong bảng user. Nếu có thì sẽ 
tiến hành check password xem có đúng không. Nếu password đúng thì dùng 
jwt.sign để chuỗi JWT với email và id của user, sau đó gửi token đã tạo đến      lOMoARcPSD| 36625228
client thông qua cookie. Nếu password sai thì trả lỗi 422 với nội dung 
password không đúng. Nếu không tìm được email thì trả lỗi not found.  2.2.3 Get profile 
app.get('/api/profile', (req,res) => { 
 mongoose.connect(process.env.MONGO_URL);   const {token} = req.cookies; 
 if (token) { jwt.verify(token, jwtSecret, {}, async (err, 
userData) => { if (err) throw err; 
 const {name,email,_id} = await User.findById(userData.id);  res.json({name,email,_id});   });   } else {   res.json(null);   }  }); 
Check token nếu có dùng jwt.verify để xác thực token và tiến hành giải 
mã token và trả name, email, và id của user đó.  2.2.4 Log out 
app.post('/api/logout', (req,res) => { 
res.cookie('token', '').json(true); }); 
Tiến hành xóa token trong cookie 
2.2.5 Upload ảnh bằng link 
app.post('/api/upload-by-link', async (req,res) => {  const {link} = req.body; 
 const newName = 'photo' + Date.now() + '.jpg'; 
 await imageDownloader.image({  url: link,   // dest: '/tmp/' +newName, 
 dest: __dirname + '/uploads/' + newName   }); 
 // const url = await uploadToS3('/tmp/' +newName, newName, mime.lookup('/tmp/' +newName));   // res.json(url); 
 res.json( 'http://localhost:4000/uploads/' + newName)  }); 
Dùng imageDownloader để tiến hành download ảnh và lưu lại với tên mới với 
đuôi file .jpg, ảnh sẽ được lưu lại ở folder uploads ở phía backend, sau đó trả  về ảnh được upload.      lOMoARcPSD| 36625228
2.2.6 Upload ảnh từ máy 
const photosMiddleware = multer({dest:'uploads/'}); 
app.post('/api/upload', photosMiddleware.array('photos', 100), async (req,res) => {  const uploadedFiles = []; 
 for (let i = 0; i < req.files.length; i++) { 
 const {path,originalname,mimetype} = req.files[i]; 
 const parts = originalname.split('.') 
const ext = parts[parts.length -1] 
 const newPath = path + "." + ext  fs.renameSync(path, newPath) 
 // const url = await uploadToS3(path, originalname, mimetype);  uploadedFiles.push(newPath);   }   res.json(uploadedFiles);  }); 
Dùng mutler để xử lí việc tải ảnh lên từ các tệp tin được gửi từ client 
photosMiddleware.array('photos', 100) định nghĩa rằng middleware 
này sẽ xử lý tệp tin được gửi dưới dạng một mảng có tên là 'photos', và 
tối đa 100 tệp tin có thể được tải lên trong một lần yêu cầu. 
Sau đó tiến hành xử lí các tệp ảnh được gửi đó bằng cách lấy ra tên file 
của từng ảnh đó và dùng fs.renameSync để tiến hành đổi tên cho các file đó 
và lưu lại vào mảng uploadedFile và trả về các ảnh đó về bên phía client.  2.2.7 Tạo place 
app.post('/api/places', (req,res) => { 
 mongoose.connect(process.env.MONGO_URL);   const {token} = req.cookies;   const { 
title,address,addedPhotos,description,price, 
perks,extraInfo,checkIn,checkOut,maxGuests, 
 } = req.body; jwt.verify(token, jwtSecret, {}, async (err, 
userData) => { if (err) throw err; 
 const placeDoc = await Place.create({  owner:userData.id,price, 
title,address,photos:addedPhotos,description, 
perks,extraInfo,checkIn,checkOut,maxGuests,   });   res.json(placeDoc);   });  }); 
Đầu tiên sẽ tiến hành xác thực token, sau đó thực hiện việc tạo nơi ở 
trong bản Place với các thông tin được gửi từ phía client và trả về thông tin đã  tạo thành công.      lOMoARcPSD| 36625228
2.2.8 Get place của user 
app.get('/api/user-places', (req,res) => { 
 mongoose.connect(process.env.MONGO_URL);   const {token} = req.cookies; 
 jwt.verify(token, jwtSecret, {}, async (err, userData) => {  const {id} = userData; 
 res.json( await Place.find({owner:id}) );  });  }); 
Đầu tiên sẽ tiến hành xác thực token, nếu đúng thì sẽ trả về những nơi mà user 
đó đã tạo thông qua userId của họ.  2.2.9 Get place by id 
app.get('/api/places/:id', async (req,res) => { 
 mongoose.connect(process.env.MONGO_URL);  const {id} = req.params; 
 res.json(await Place.findById(id));  }); 
Dùng findById để trả về nơi theo id được truyền từ client. 
2.2.10 Chỉnh sửa nơi ở 
app.put('/api/places', async (req,res) => { 
mongoose.connect(process.env.MONGO_URL);   const {token} = req.cookies;   const { 
 id, title,address,addedPhotos,description, 
 perks,extraInfo,checkIn,checkOut,maxGuests,price,   } = req.body; 
 jwt.verify(token, jwtSecret, {}, async (err, userData) => {  if (err) throw err; 
 const placeDoc = await Place.findById(id); if 
(userData.id === placeDoc.owner.toString()) {  placeDoc.set({ 
 title,address,photos:addedPhotos,description, 
perks,extraInfo,checkIn,checkOut,maxGuests,price,   });   await placeDoc.save();   res.json('ok');   }   });  }); 
Tiến hành xác thực token, nếu đúng thì sẽ dùng findById để tìm đến 
nơi ở đó theo id, sau đó kiểm tra thông tin id của user đang cần chỉnh sửa và 
id của người tạo xem đúng không, nếu đúng thì sẽ tiến hành lưu lại các thông 
tin cần chỉnh sửa và trả về kết quả cập nhật thành công.      lOMoARcPSD| 36625228 2.2.11 Get place 
app.get('/api/places', async (req,res) => { 
mongoose.connect(process.env.MONGO_URL); 
 res.json( await Place.find() );  }); 
Dùng find() để lấy ra được tất cả các nơi trong bảng Place  2.2.12 Đặt chỗ 
app.post('/api/bookings', async (req, res) => { 
mongoose.connect(process.env.MONGO_URL); 
 const userData = await getUserDataFromReq(req);  const { 
 place,checkIn,checkOut,numberOfGuests,name,phone,price, 
} = req.body; Booking.create({ 
 place,checkIn,checkOut,numberOfGuests,name,phone,price, 
user:userData.id, }).then((doc) => { res.json(doc); 
}).catch((err) => { throw err;   });  }); 
Tiến hành xác thực token để lấy user id, sau đó tiến hành tạo đơn trong bảng 
Booking với dữ liệu được truyền từ bên phía client và trả về thông tin đơn đã  được đặt thành công.  2.2.13 Get booking 
app.get('/api/bookings', async (req,res) => { 
mongoose.connect(process.env.MONGO_URL); 
const userData = await getUserDataFromReq(req); 
 res.json( await Booking.find({user:userData.id}).populate('place') );  }); 
Tiến hành xác thực token và trả về thông tin booking trong bảng Booking  thông qua id của user.      lOMoARcPSD| 36625228 2.2.14 Hủy booking 
app.delete('/api/bookings/:id', async (req, res) => { 
mongoose.connect(process.env.MONGO_URL); 
 const bookingId = req.params.id; 
 const booking = await Booking.findById(bookingId);     try { 
 const booking = await Booking.findById(bookingId);   if (!booking) { 
 return res.status(404).json({ message: 'Booking not found' });   } 
 await Booking.findByIdAndDelete(bookingId); 
 res.json({ message: 'Booking deleted successfully' });   } catch (error) {  console.error(error); 
 res.status(500).json({ message: 'Internal server error' });   }  }); 
Tìm đơn hàng trong bảng Booking thông qua id được truyền từ client. 
Sau đó tiến hành check xem có id đó không, nếu không thì thông báo lỗi 
booking not found, nếu có thì dùng findByIdAndDelete để tiến hành xóa dữ 
liệu trong bảng Booking thông qua id đó và trả về xóa thành công.  2.3. FrontEnd 
2.3.1. Giao diện Trang chủ: 
- Gọi api get places để lấy ra tất cả các phòng trong hệ thống sau đó hiển thị  lên trang người dùng          lOMoARcPSD| 36625228  
2.3.2 Giao diện trang Đăng nhập 
- Gọi api login và truyền vào thông tin đăng nhập để tiến hành đăng nhập, sau 
đó dùng UseContext để tiến hành lưu trữ thông tin đăng nhập và hiển thị tên 
người dùng trên trang web 
 async function handleLoginSubmit(ev) {   ev.preventDefault(); try { 
 const {data} = await axios.post('/login', {email,password});   setUser(data);   alert('Login successful');   setRedirect(true);   } catch (e) {   alert('Login failed');   }   }   if (redirect) {      lOMoARcPSD| 36625228  return } 
Đăng nhập thành công thì chuyển đến trang chủ   
2.3.3 Giao diện trang đăng ký 
- Gọi api register và truyền vào thông tin đăng kí để tiến hành đăng kí, nếu 
đăng kí thành công thì sẽ chuyển đến trang đăng nhập, sai thì sẽ thông báo lỗi 
async function registerUser(ev) {   ev.preventDefault(); try { 
 await axios.post('/register', {   name,   email,   password,   });      lOMoARcPSD| 36625228
 alert('Registration successful. Now you can log in');   setRedirect(true);   } catch (e) { 
 alert('Registration failed. Please try again later');   }   }   if (redirect) {   return ; }   
2.3.4 Giao diện trang Tài khoản 
Dùng UserContext để hiển thị thông tin user và gọi api logout nếu 
muốn đăng xuất. Nếu chưa đăng nhập thì sẽ chuyển đến trang login 
const [redirect,setRedirect] = useState(null); const {ready,user,setUser} =  useContext(UserContext);   let {subpage} = useParams();      lOMoARcPSD| 36625228  if (subpage === undefined) {   subpage = 'profile'; }   async function logout() {   await axios.post('/logout');   setRedirect('/');   setUser(null); }   // if (!ready) {   // return 'Loading...'; // } 
 if (ready && !user && !redirect) {   return }   if (redirect) {   return } 
Trong UseContext gọi api get profile để lấy ra thông tin user  useEffect(() => {   if (!user) { 
 axios.get('/profile').then(({data}) => {   setUser(data);   setReady(true);   });   }   }, []);   return (     {children}     );      lOMoARcPSD| 36625228  
2.3.5 Giao diện trang chi tiết nơi ở  - 
Gọi api get place by id và truyền id của phòng được chọn để lấy được 
thông tin chi tiết của phòng đó và hiển thị lên trên giao diện   useEffect(() => {   if (!id) {   return;   } 
 axios.get(`/places/${id}`).then(response => { setPlace(response.data);   });   }, [id]);   if (!place) return '';      lOMoARcPSD| 36625228         lOMoARcPSD| 36625228 - 
Gọi api booking và truyền thời gian, số lượng người, tên, số điện thoại 
để tiến hành đặt phòng 
async function bookThisPlace() { 
 const response = await axios.post('/bookings', { 
 checkIn,checkOut,numberOfGuests,name,phone,   place:place._id, 
 price:numberOfNights * place.price,   }); 
 const bookingId = response.data._id; 
 setRedirect(`/account/bookings/${bookingId}`); } 
2.3.6 Giao diện trang Booking 
- Gọi api get booking và tìm đến đơn có id bằng id trên url để lấy ra được 
thông tin chi tết của đơn hàng đó  useEffect(() => {   if (id) { 
 axios.get('/bookings').then(response => { 
 const foundBooking = response.data.find(({_id}) => _id === id);   if (foundBooking) {   setBooking(foundBooking);   } });   }   }, [id]); 
- Gọi api delete booking và truyền id vào để tiến hành xóa đơn hàng      lOMoARcPSD| 36625228
const handleDeleteOrder = async() => { const userConfirmed  = window.confirm( 
 "Bạn có chắAc muốAn huCy đơn đặt phòng khống?" ); 
 // NếAu người dùng đã xác nhận, thực hiện xóa 
 if (userConfirmed && id) {   axios   .delete(`/bookings/${id}`)   .then((response) => { 
 if (response?.data.message === "Booking deleted successfully") { 
 alert("Đã xóa đơn đặt phòng thành cống!");   window.location.reload();   }   })   .catch((error) => { 
 console.error("Error deleting order:", error); alert("Đã xaCy ra lốTi khi xóa  đơn đặt phòng.");   });   }   }      lOMoARcPSD| 36625228  
2.3.7 Giao diện trang My Booking 
- Gọi api get booking để lấy ra toàn bộ đơn hàng và hiển thị lên giao diện  useEffect(() => { 
 axios.get('/bookings').then(response => {   setBookings(response.data);   });   }, []);      lOMoARcPSD| 36625228  
2.3.8 Giao diện trang My accommodations 
- Gọi api get user-place để lấy được tất cả nơi mà user này đã đăng  useEffect(() => { 
 axios.get('/user-places').then(({data}) => {   setPlaces(data);   });   }, []);      lOMoARcPSD| 36625228  
2.3.9 Giao diện trang thêm nơi ở mới 
- Gọi api get place by id để tiến hành truyền dữ liệu vào các ô input để tiến  hành update dữ liệu 
useEffect(() => { if (!id) {   return;      lOMoAR cPSD| 36625228  } 
 axios.get('/places/'+id).then(response => {   const {data} = response;   setTitle(data.title);   setAddress(data.address);   setAddedPhotos(data.photos); 
 setDescription(data.description);   setPerks(data.perks); 
 setExtraInfo(data.extraInfo);   setCheckIn(data.checkIn);   setCheckOut(data.checkOut); 
 setMaxGuests(data.maxGuests);   setPrice(data.price);   }); }, [id]); 
async function savePlace(ev) {   ev.preventDefault();   const placeData = {   title, address, addedPhotos, 
 description, perks, extraInfo, 
 checkIn, checkOut, maxGuests, price,   };   if (id) {   // update   await axios.put('/places', {   id, ...placeData   });   setRedirect(true);   } else {   // new place 
 await axios.post('/places', placeData);   setRedirect(true);   }   } 
Nếu tạo mới thì sẽ gọi api post places để tạo nơi ở mới 
- Ở phần hình ảnh: gọi api upload by link nếu tải ảnh bằng link và gọi api 
upload nếu tải ảnh từ thiết bị      lOMoARcPSD| 36625228
async function addPhotoByLink(ev) {   ev.preventDefault(); 
 const {data:filename} = await axios.post('/upload-by-link',  {link: photoLink});   onChange(prev => { if  (filename) {   return [...prev, filename];   }   return prev;   });   setPhotoLink('');   } 
function uploadPhoto(ev) { const files = ev.target.files;   const data = new FormData(); 
 for (let i = 0; i < files.length; i++) { 
 data.append('photos', files[i]);   } 
 axios.post('/upload', data, { 
 headers: {'Content-type':'multipart/form-data'}   }).then(response => { 
 const {data:filenames} = response;   onChange(prev => { 
 return [...prev, ...filenames];   });   })   } 
Dùng 'Content-type':'multipart/form-data' để có thể gửi nhiều file cùng lúc      lOMoARcPSD| 36625228       lOMoARcPSD| 36625228  
Chương 3. Cài đặt và kiểm thử  3.1. Cài đặt:  3.1.1 Back end: 
- Bước 1: Mở terminal và cd đến folder api 
- Bước 2: Tạo một .env với nội dung là đường link kết nối với mongoodb 
MONGO_URL = mongodb+srv://booking:gvF7bIzlGMh40ptv@cluster0.jhiwsro.mongodb.net/? 
retryWrites=true&w=majority 
- Bước 3 : Tạo folder uploads trong folder api 
- Bước 4: chạy câu lệnh npm install để download node modules- Bước 5: 
chạy câu lệnh npm start để khởi động  3.1.2 Front end: 
- Bước 1: Mở terminal và cd đến folder client 
- Bước 2: Tạo file .evn với nội dung là url của backend 
VITE_API_BASE_URL = http://localhost:4000/api      lOMoARcPSD| 36625228
- Bước 3: Chạy câu lệnh npm install để download node modules 
- Bước 4: Chạy câu lệnh npm run dev để khởi động chương trình 
- Bước 5: Truy cập đường dẫn http://localhost:5173/ 
3.2. Demo chương trình  - Trang chủ:   
- Đăng ký: Chọn vào avatar phía trên góc phải ở trang chủ để chuyển đến 
trang đăng nhập. Sau đó chọn “Register now” để chuyển đến trang đăng ký 
và nhập thông tin đăng ký rồi nhấn “Register”      lOMoARcPSD| 36625228  
Sau khi đăng kí thành công trang sẽ chuyển đến trang đăng nhập   
- Đăng nhập: Chọn vào avatar phía trên góc phải ở trang chủ để chuyển đến 
trang đăng nhập. Sau đó nhập thông tin đăng nhập và bấm “Login”      lOMoARcPSD| 36625228  
Sau khi đăng nhập thành công thì sẽ chuyển đến trang chủ        lOMoARcPSD| 36625228
- Xem thông tin chi tiết của từng phòng: Ở trang chủ, ta sẽ chọn phòng mà 
chúng ta muốn xem. Trang web sẽ chuyển đến trang xem thông tin chi tiết 
của phòng đó và hiển thị tất cả thông tin của phòng đó bao gồm hình ảnh, 
mô tả, vị trí, giá, ….        lOMoARcPSD| 36625228  
- Booking: Khi chọn được phòng mong muốn, người dùng sẽ tiến hành nhập 
thời gian checkIn, checkOut, số lượng người, tên, số điện thoại và nhấn 
“Booking this place” để đặt hàng      lOMoARcPSD| 36625228  
Sau khi đặt hàng thành công thì trang sẽ chuyển đến trang chi tiết đơn hàng      lOMoARcPSD| 36625228  
- Hủy đơn đặt hàng: Khi booking thành công thì trang sẽ chuyển đến chi tiết 
đơn hàng, nếu muốn hủy đơn thì nhấn chọn “Cancel order” và xác nhận 
hủy. Hoặc người dùng có thể chọn vào tên của mình ở phía trên bên phải 
trang web và chọn vào “My booking” sau đó chọn đến nơi mà bạn muốn 
hủy nhấn chọn vào nơi đó và nhấn “Cancel order” và xác nhận hủy.      lOMoARcPSD| 36625228         lOMoARcPSD| 36625228       lOMoARcPSD| 36625228  
- Xem và chỉnh sửa các nơi đã đăng: Chọn vào tên người dùng ở phía trên 
bên phải trang web và chọn “My accommodation” để xem tất cả các nơi đã  đăng      lOMoARcPSD| 36625228  
Nếu muốn chỉnh thử thông tin của nơi nào thì chọn vào nơi đó trang web sẽ 
chuyển đến trang cập nhật và nhập nội dung cần chỉnh sửa vào và nhấn  “Save”      lOMoARcPSD| 36625228       lOMoARcPSD| 36625228  
- Thêm nơi ở mới: Chọn vào “Add new place” ở trong “My 
accommodation” sao đó nhập tất cả các thông tin cần thiết và hình ảnh(có 
thể tải bằng link hoặc từ thiết bị cá nhân) và nhấn “Save” để đăng nơi ở  mới.      lOMoARcPSD| 36625228  
Nếu upload ảnh bằng link thì sẽ dán link ảnh vào và nhấn “Add photo”      lOMoARcPSD| 36625228  
Nếu tải ảnh từ thiết bị thì nhấn chọn “Upload” và tải ảnh lên và có thể tải lên  nhiều ảnh cung lúc      lOMoARcPSD| 36625228  
Thêm các thông tin cần thiết và giá phòng vào và nhấn “Save”        lOMoARcPSD| 36625228
Nơi ở mới đã được thêm   
- Đăng xuất: Chọn “Log out” trong My profile để tiến hành đăng xuất      lOMoARcPSD| 36625228         lOMoAR cPSD| 36625228
Chương 4. Kết Luận  41. Kết Luận: 
Về cơ bản, em tự nhận xét rằng em đã cơ bản hoàn thành phần yêu cầu đề ra, 
và sau đây là một số ưu điểm và nhược điểm rút ra từ web Booking App:  - Về ưu điểm: 
+ Giao diện dễ sử dụng. 
+ Các chức năng được thể hiện rõ ràng. 
+ Chương trình nhẹ, hoạt động mượt mà.  Về nhược điểm 
+ Các chức năng còn cơ bản và chưa thật sự được tối ưu. 
+ Thiết kế còn đơn giản. 
4.2. Hướng phát triển 
- Hoàn thiện các tính năng.  - Upload ảnh lên cloud. 
- Cải thiện trải nghiệm người dùng. 
- Thêm nhiều tính năng mới hơn để hoàn thiện tốt nhất trang web. 
- Phát triển giao diện đẹp mắt hơn.    
