├── public ├── robots.txt ├── favicon.ico ├── logo192.png ├── logo512.png ├── manifest.json └── index.html ├── src ├── images │ ├── room-1.jpeg │ ├── room-3.jpeg │ ├── gif │ │ ├── loading-gear.gif │ │ └── loading-arrow.gif │ └── notfound.svg ├── Redux │ ├── Store.js │ └── Reducer.js ├── Components │ ├── Title.jsx │ ├── Rooms.jsx │ ├── Banner.jsx │ ├── Loading.jsx │ ├── StyledHero.jsx │ ├── ProtectedRoute.js │ ├── RoomsContainer.jsx │ ├── Room.jsx │ ├── RoomsList.jsx │ ├── Users.jsx │ ├── Login.jsx │ ├── Bookings.jsx │ ├── Navbar.jsx │ ├── SingleRooms.jsx │ ├── AddRooms.jsx │ └── updateRoom.jsx ├── index.js ├── firebase.js ├── index.css ├── contexts │ └── UserAuthContext.js ├── App.js └── App.css ├── .gitignore ├── README.md └── package.json /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nabia-Sheikh/hotel-management-admin/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nabia-Sheikh/hotel-management-admin/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nabia-Sheikh/hotel-management-admin/HEAD/public/logo512.png -------------------------------------------------------------------------------- /src/images/room-1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nabia-Sheikh/hotel-management-admin/HEAD/src/images/room-1.jpeg -------------------------------------------------------------------------------- /src/images/room-3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nabia-Sheikh/hotel-management-admin/HEAD/src/images/room-3.jpeg -------------------------------------------------------------------------------- /src/images/gif/loading-gear.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nabia-Sheikh/hotel-management-admin/HEAD/src/images/gif/loading-gear.gif -------------------------------------------------------------------------------- /src/images/gif/loading-arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nabia-Sheikh/hotel-management-admin/HEAD/src/images/gif/loading-arrow.gif -------------------------------------------------------------------------------- /src/Redux/Store.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "redux"; 2 | import { reducer } from "./Reducer"; 3 | 4 | export const store = createStore(reducer); -------------------------------------------------------------------------------- /src/Components/Title.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default function Title({ title }) { 4 | return ( 5 |
6 |

{title}

7 |
8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/Components/Rooms.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import RoomsContainer from "./RoomsContainer"; 3 | const Rooms = () => { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | }; 10 | 11 | export default Rooms; 12 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import App from './App'; 5 | import { store } from './Redux/Store'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | -------------------------------------------------------------------------------- /src/Components/Banner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Banner = ({children , title , subtitle}) => { 4 | return ( 5 |
6 |

{title}

7 |
8 |

{subtitle}

9 | {children} 10 |
11 | ); 12 | } 13 | 14 | export default Banner 15 | -------------------------------------------------------------------------------- /src/Components/Loading.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import loadingGif from "../images/gif/loading-arrow.gif"; 3 | export default function Loading({message}) { 4 | return ( 5 |
6 |

{message}

7 | loading please wait 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/Components/StyledHero.jsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | import defaultBcg from '../images/room-3.jpeg'; 3 | 4 | const StyledHero = styled.header` 5 | min-height: 100vh; 6 | background: url(${props => props.img ? props.img : defaultBcg}) center/cover no-repeat; 7 | display: flex; 8 | align-items: center; 9 | justify-content: center; 10 | `; 11 | 12 | export default StyledHero; -------------------------------------------------------------------------------- /src/Components/ProtectedRoute.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Navigate } from "react-router-dom"; 3 | import { useUserAuth } from "../contexts/UserAuthContext"; 4 | 5 | const ProtectedRoute = ({ children }) => { 6 | const { user } = useUserAuth(); 7 | 8 | if (!user) { 9 | return ; 10 | } 11 | return children; 12 | }; 13 | 14 | export default ProtectedRoute; 15 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/Components/RoomsContainer.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import RoomsList from "./RoomsList"; 3 | import Loading from "./Loading"; 4 | import { useSelector } from "react-redux"; 5 | 6 | export default function RoomsContainer() { 7 | const state = useSelector((state) => state); 8 | 9 | return ( 10 | <> 11 | {state.length > 0 ? ( 12 | 13 | 14 | 15 | ) : ( 16 | <> 17 | 18 | 19 | )} 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/firebase.js: -------------------------------------------------------------------------------- 1 | import { initializeApp } from "firebase/app"; 2 | import { getAuth } from "firebase/auth"; 3 | import { getDatabase } from "firebase/database" 4 | 5 | const firebaseConfig = { 6 | apiKey: "AIzaSyDzha_p5FDDTlfpUy2x59R_1uHUP2eILtw", 7 | authDomain: "jawanpakhackathon.firebaseapp.com", 8 | projectId: "jawanpakhackathon", 9 | storageBucket: "jawanpakhackathon.appspot.com", 10 | messagingSenderId: "845328112334", 11 | appId: "1:845328112334:web:80cb6396f82ad915ea4e9f" 12 | }; 13 | // Initialize Firebase 14 | const app = initializeApp(firebaseConfig); 15 | 16 | 17 | export const auth = getAuth(app); 18 | export const db = getDatabase(); 19 | export default app; 20 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Nunito&display=swap'); 2 | *{ 3 | 4 | font-family: 'Nunito', sans-serif; 5 | } 6 | 7 | ::-webkit-scrollbar { 8 | width: 8px; 9 | } 10 | 11 | ::-webkit-scrollbar-thumb { 12 | background: linear-gradient(transparent, #0000ff); 13 | border-radius: 12px; 14 | } 15 | 16 | ::-webkit-scrollbar-thumb:hover { 17 | background: linear-gradient(#D7DBDD, #0000ff); 18 | } 19 | 20 | @media (max-width: 576px) { 21 | ::-webkit-scrollbar { 22 | width: 4px; 23 | } 24 | 25 | ::-webkit-scrollbar-thumb { 26 | background: linear-gradient(transparent, #0000ff); 27 | border-radius: 6px; 28 | } 29 | 30 | ::-webkit-scrollbar-thumb:hover { 31 | background: linear-gradient(#D7DBDD, #0000ff); 32 | } 33 | } -------------------------------------------------------------------------------- /src/Components/Room.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import defaultImg from "../images/room-1.jpeg"; 4 | 5 | export default function Room({ room }) { 6 | const { name, slug, images, price } = room; 7 | return ( 8 |
9 |
10 | single room 15 |
16 |
Rs {price}
17 |

per night

18 |
19 | 23 | Features 24 | 25 |

{name}

26 |
27 |
28 | ); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Admin Panel of Hotel Management System 3 | 4 | This project is part of the Course of Web & Hybrid development which is taken at Grand Hackathon. 5 | 6 | ## Demo of Admin Panel 7 | 8 | https://hotel-admin-by-nabia.netlify.app/ 9 | 10 | ## Email : admin@gmail.com 11 | ## Password : adminadmin 12 | 13 | ## Demo of Site 14 | 15 | https://hotel-management-by-nabia.netlify.app/ 16 | 17 | 18 | 19 | ## Features 20 | 21 | - Rooms list 22 | - Single page of Rooms 23 | - Add/update/Delete rooms 24 | - Users list 25 | - Booking details 26 | - Handle bookings 27 | - Validation of admins. 28 | 29 | ## Tech Stack 30 | 31 | **Client:** React, Redux, React-Bootstrap , Bootstrap , Context API 32 | 33 | **Server:** Firebase Realtime Database, Firebase Authentication 34 | 35 | 36 | ## Run Locally 37 | 38 | Clone the project 39 | 40 | ```bash 41 | git clone https://github.com/Nabia-Sheikh/hotel-management-admin.git 42 | ``` 43 | 44 | Go to the project directory 45 | 46 | ```bash 47 | cd hotel-management-system 48 | ``` 49 | 50 | Install dependencies 51 | 52 | ```bash 53 | npm install 54 | ``` 55 | 56 | Start the server 57 | 58 | ```bash 59 | npm start 60 | ``` 61 | 62 | -------------------------------------------------------------------------------- /src/Components/RoomsList.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Room from "./Room"; 3 | import notFound from "../images/notfound.svg"; 4 | 5 | export default function RoomsList(props) { 6 | const { rooms : data } = props; 7 | return ( 8 | <> 9 | {!data ? ( 10 | <> 11 |
12 |
13 |
14 |
15 | not found 16 |
17 |
18 |
19 |

20 | Unfortunately no rooms matched your search parameters 21 |

22 |
23 |
24 |
25 |
26 |
27 | 28 | ) : ( 29 |
30 |
31 | {data.map((item) => { 32 | return ; 33 | })} 34 |
35 |
36 | )} 37 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src/Components/Users.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Table } from "react-bootstrap"; 3 | import { useSelector } from "react-redux"; 4 | import Loading from "./Loading"; 5 | 6 | const Users = () => { 7 | const state = useSelector((state) => state); 8 | 9 | return ( 10 | <> 11 | {state[1] ? ( 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {Object.values(state[1]).map((item) => ( 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ))} 38 | 39 | 40 |
IDNameEmailPhone No.Role
{item.id}{item.name}{item.email}{item.number}{item.isAdmin ? "Admin" : "User"}
41 | ) : ( 42 | 43 | )} 44 | 45 | ); 46 | }; 47 | 48 | export default Users; 49 | -------------------------------------------------------------------------------- /src/Redux/Reducer.js: -------------------------------------------------------------------------------- 1 | const initialState = []; 2 | 3 | function formatData(items) { 4 | let tempItems = Object.values(items).map((item) => { 5 | let id = item.sys.id; 6 | let images = item.fields.images.map((image) => image.fields.file.url); 7 | let room = { ...item.fields, images, id }; 8 | return room; 9 | }); 10 | return tempItems; 11 | } 12 | 13 | export const reducer = (state = initialState, { type, payload }) => { 14 | switch (type) { 15 | case "FIREBASE": 16 | let rooms = formatData(payload.outData.hotels); 17 | let temp = []; 18 | for (let i of rooms) i && temp.push(i); 19 | rooms = temp; 20 | let featuredRooms = rooms.filter((room) => room.featured === true); 21 | let slug = rooms[0].slug; 22 | let maxPrice = Math.max(...rooms.map((item) => item.price)); 23 | let maxSize = Math.max(...rooms.map((item) => item.size)); 24 | 25 | const roomsData = [ 26 | { 27 | slug, 28 | rooms, 29 | featuredRooms, 30 | sortedRooms: rooms, 31 | loading: false, 32 | price: maxPrice, 33 | maxPrice, 34 | maxSize, 35 | breakfast: false, 36 | pets: false, 37 | type: "all", 38 | capacity: 1, 39 | minPrice: 0, 40 | minSize: 0, 41 | }, 42 | ]; 43 | const users = payload.outData.users; 44 | 45 | return [roomsData, users]; 46 | 47 | default: 48 | return state; 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hotel-admin", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/react": "^11.7.1", 7 | "@emotion/styled": "^11.6.0", 8 | "@material-ui/core": "^4.12.3", 9 | "@material-ui/icons": "^4.11.2", 10 | "@material-ui/lab": "^4.0.0-alpha.60", 11 | "@material-ui/styles": "^4.11.4", 12 | "@mui/material": "^5.2.6", 13 | "@testing-library/jest-dom": "^5.16.1", 14 | "@testing-library/react": "^12.1.2", 15 | "@testing-library/user-event": "^13.5.0", 16 | "bootstrap": "^4.5.0", 17 | "firebase": "^9.4.1", 18 | "jquery": "^3.6.0", 19 | "popper.js": "^1.16.1", 20 | "react": "^17.0.2", 21 | "react-bootstrap": "^2.0.4", 22 | "react-dom": "^17.0.2", 23 | "react-icons": "^4.3.1", 24 | "react-redux": "^7.2.6", 25 | "react-router-dom": "^6.2.1", 26 | "react-scripts": "5.0.0", 27 | "redux": "^4.1.2", 28 | "sass": "^1.45.1", 29 | "styled-components": "^5.3.3", 30 | "uuid": "^8.3.2", 31 | "web-vitals": "^2.1.2" 32 | }, 33 | "scripts": { 34 | "start": "react-scripts start", 35 | "build": "react-scripts build", 36 | "test": "react-scripts test", 37 | "eject": "react-scripts eject" 38 | }, 39 | "eslintConfig": { 40 | "extends": [ 41 | "react-app", 42 | "react-app/jest" 43 | ] 44 | }, 45 | "browserslist": { 46 | "production": [ 47 | ">0.2%", 48 | "not dead", 49 | "not op_mini all" 50 | ], 51 | "development": [ 52 | "last 1 chrome version", 53 | "last 1 firefox version", 54 | "last 1 safari version" 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/contexts/UserAuthContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext, useEffect, useState } from "react"; 2 | 3 | import { 4 | signInWithEmailAndPassword, 5 | onAuthStateChanged, 6 | signOut, 7 | } from "firebase/auth"; 8 | 9 | import { auth, db } from "../firebase"; 10 | 11 | import { child, get, ref } from "firebase/database"; 12 | import { useNavigate } from "react-router-dom"; 13 | 14 | export const userAuthContext = createContext(); 15 | 16 | 17 | export function UserAuthContextProvider({ children }) { 18 | const [user, setUser] = useState({}); 19 | const navigate = useNavigate(); 20 | 21 | 22 | function logIn(email, password) { 23 | get(child(ref(db), "/users")).then((data) => { 24 | const userAuth = Object.values(data.val()).filter( 25 | (item) => item.email === email && item.isAdmin === true 26 | ); 27 | if (userAuth[0]) { 28 | return signInWithEmailAndPassword(auth, email, password).then(()=>navigate("/rooms")) 29 | } 30 | alert("Please Sign in with Admin Account."); 31 | }); 32 | } 33 | 34 | 35 | function logOut() { 36 | return signOut(auth); 37 | } 38 | 39 | 40 | useEffect(() => { 41 | const unsubscribe = onAuthStateChanged(auth, (currentuser) => { 42 | setUser(currentuser); 43 | }); 44 | 45 | return () => { 46 | unsubscribe(); 47 | }; 48 | }, []); 49 | 50 | return ( 51 | 54 | {children} 55 | 56 | ); 57 | } 58 | 59 | export function useUserAuth() { 60 | return useContext(userAuthContext); 61 | } 62 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 19 | 20 | 29 | Hotel Management admin. 30 | 31 | 32 | 33 |
34 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/Components/Login.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | import { Form, Alert } from "react-bootstrap"; 4 | import { useUserAuth } from "../contexts/UserAuthContext"; 5 | import styled from "styled-components"; 6 | 7 | const Button = styled.button` 8 | background-color: blue; 9 | padding: 10px; 10 | border-radius: 5px; 11 | color: white; 12 | border: none; 13 | font-size: 20px; 14 | width: 100%; 15 | 16 | &:hover { 17 | background-color: white; 18 | color: blue; 19 | border: 2px solid blue; 20 | } 21 | `; 22 | 23 | const Login = () => { 24 | const [email, setEmail] = useState(""); 25 | const [password, setPassword] = useState(""); 26 | const [error, setError] = useState(""); 27 | const { logIn} = useUserAuth(); 28 | const navigate = useNavigate(); 29 | 30 | const handleSubmit = async (e) => { 31 | e.preventDefault(); 32 | setError(""); 33 | try { 34 | await logIn(email, password); 35 | navigate("/rooms"); 36 | } catch (err) { 37 | setError(err.message); 38 | } 39 | }; 40 | 41 | 42 | 43 | return ( 44 | <> 45 |
46 |

Login

47 | {error && {error}} 48 |
49 | 50 | setEmail(e.target.value)} 54 | /> 55 | 56 | 57 | 58 | setPassword(e.target.value)} 62 | /> 63 | 64 | 65 |
66 | 69 |
70 |
71 |
72 |
73 | 74 | ); 75 | }; 76 | 77 | export default Login; 78 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import { BrowserRouter, Route, Routes } from "react-router-dom"; 2 | import "./App.css"; 3 | import "../node_modules/bootstrap/dist/css/bootstrap.min.css"; 4 | import "../node_modules/bootstrap/dist/js/bootstrap.min.js"; 5 | import Navbar from "./Components/Navbar"; 6 | import Rooms from "./Components/Rooms"; 7 | import { onValue, ref } from "firebase/database"; 8 | import { db } from "./firebase"; 9 | import { useEffect } from "react"; 10 | import { useDispatch } from "react-redux"; 11 | import SingleRooms from "./Components/SingleRooms"; 12 | import AddRooms from "./Components/AddRooms"; 13 | import UpdateRoom from "./Components/updateRoom"; 14 | import Users from "./Components/Users"; 15 | import Bookings from "./Components/Bookings"; 16 | import { UserAuthContextProvider } from "./contexts/UserAuthContext"; 17 | import ProtectedRoute from "./Components/ProtectedRoute"; 18 | import Login from "./Components/Login"; 19 | 20 | function App() { 21 | const dispatch = useDispatch(); 22 | const getFromFirebase = () => { 23 | const dbRef = ref(db); 24 | 25 | 26 | onValue(dbRef, (snapshot) => { 27 | const outData = snapshot.val(); 28 | dispatch({ 29 | type: "FIREBASE", 30 | payload: { 31 | outData, 32 | }, 33 | }); 34 | }); 35 | }; 36 | 37 | useEffect(() => { 38 | getFromFirebase(); 39 | // eslint-disable-next-line react-hooks/exhaustive-deps 40 | }, []); 41 | 42 | return ( 43 | 44 | 45 | 46 | 47 | } /> 48 | } /> 49 | } /> 50 | } /> 51 | } /> 52 | } /> 53 | } /> 54 | } /> 55 | 56 | 57 | 58 | ); 59 | } 60 | 61 | export default App; 62 | -------------------------------------------------------------------------------- /src/Components/Bookings.jsx: -------------------------------------------------------------------------------- 1 | import { onValue, ref, update } from "firebase/database"; 2 | import React, { useState } from "react"; 3 | import Table from "react-bootstrap/Table"; 4 | import { db } from "../firebase"; 5 | import { Link } from "react-router-dom"; 6 | import styled from "styled-components"; 7 | import { FaCheckCircle, FaTimesCircle } from "react-icons/fa"; 8 | 9 | const StatusTD = styled.td` 10 | font-weight: bold; 11 | color: ${(props) => (props.type === "Pending" ? "blue" : "")}; 12 | color: ${(props) => (props.type === "Accepted" ? "green" : "")}; 13 | color: ${(props) => (props.type === "Rejected" ? "red" : "")}; 14 | `; 15 | const Bookings = () => { 16 | const [bookings, setBookings] = useState([]); 17 | 18 | React.useEffect(() => { 19 | onValue(ref(db, "/bookings/"), (snapshot) => { 20 | setBookings([]); 21 | const data = snapshot.val(); 22 | if (data !== null) { 23 | // eslint-disable-next-line array-callback-return 24 | Object.values(data).map((booking) => { 25 | setBookings((oldArray) => [...oldArray, booking]); 26 | }); 27 | } 28 | }); 29 | // eslint-disable-next-line react-hooks/exhaustive-deps 30 | }, []); 31 | 32 | 33 | 34 | const updateBooking = (bookingNumb, status) => { 35 | update(ref(db, `bookings/${bookingNumb}`), { 36 | status, 37 | }); 38 | }; 39 | 40 | console.log(bookings); 41 | return ( 42 | <> 43 | {bookings ? ( 44 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | {bookings.map((booking) => ( 66 | 67 | <> 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | {booking.status} 77 | {booking.status === "Pending" ? ( 78 | <> 79 | 89 | 99 | 100 | ) : ( 101 | <> 102 | )} 103 | 104 | 105 | ))} 106 | 107 |
IDEmailNameRoom typeStart DateEnd DateCapactiyPriceStatus
{booking.id}{booking.refID}{booking.name}{booking.type && booking.type.toUpperCase()}{booking.startDate}{booking.endDate}{booking.capacity}{booking.totalPrice} 80 | updateBooking(booking.id, "Accepted")} 87 | /> 88 | 90 | updateBooking(booking.id, "Rejected")} 97 | /> 98 |
108 | ) : ( 109 |
110 |
111 |
112 |
113 |

No bookings.

114 | 115 | No Bookings 116 | 117 |
118 |
119 |
120 |
121 | )} 122 | 123 | ); 124 | }; 125 | 126 | export default Bookings; 127 | -------------------------------------------------------------------------------- /src/Components/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { NavLink, useNavigate } from "react-router-dom"; 3 | import { FaAlignRight } from "react-icons/fa"; 4 | import { useUserAuth } from "../contexts/UserAuthContext"; 5 | 6 | const Navbar = () => { 7 | const { user , logOut } = useUserAuth(); 8 | const navigate = useNavigate(); 9 | 10 | async function handleLogout() { 11 | try { 12 | await logOut(); 13 | navigate("/"); 14 | } catch { 15 | console.log("can't logut"); 16 | } 17 | } 18 | return ( 19 | <> 20 | { 21 | user? 22 | <> 23 | 117 | 118 | : 119 | <> 120 | 132 | 133 | } 134 | 135 | 136 | ); 137 | }; 138 | export default Navbar; 139 | -------------------------------------------------------------------------------- /src/Components/SingleRooms.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useSelector } from "react-redux"; 3 | import { Link, useNavigate, useParams } from "react-router-dom"; 4 | import Banner from "./Banner"; 5 | import StyledHero from "../Components/StyledHero"; 6 | import { ref, remove } from "firebase/database"; 7 | import { db } from "../firebase"; 8 | 9 | const SingleRooms = () => { 10 | const { slug } = useParams(); 11 | const navigate = useNavigate(); 12 | const state = useSelector((state) => state); 13 | 14 | function getRoom(arg) { 15 | const idiRooms = state[0][0].rooms.map((item) => item); 16 | const roomDatas = idiRooms.filter((roomItem) => roomItem.slug === arg); 17 | return roomDatas; 18 | } 19 | if (state.length > 0 && slug) { 20 | var roomData = getRoom(slug); 21 | if (roomData.length > 0) { 22 | var id = roomData[0].id; 23 | var name = roomData[0].name; 24 | var description = roomData[0].description; 25 | var capacity = roomData[0].capacity; 26 | var size = roomData[0].size; 27 | var price = roomData[0].price; 28 | var extras = roomData[0].extras; 29 | var breakfast = roomData[0].breakfast; 30 | var pets = roomData[0].pets; 31 | var images = roomData[0].images; 32 | var [...defaultBcg] = images; 33 | } 34 | } 35 | 36 | const deleteRoom = () => { 37 | remove(ref(db, `/hotels/${id}`)).then(() => { 38 | alert("Room deleted Succesfully!"); 39 | navigate("/rooms"); 40 | }); 41 | }; 42 | 43 | return ( 44 | <> 45 | {roomData.length > 0 ? ( 46 | <> 47 | 48 | 49 | 50 | Back To Rooms 51 | 52 | 53 | 54 |
55 |
56 | {defaultBcg.map((item, index) => { 57 | return ( 58 |
59 |
60 | {name} 66 |
67 |
68 | ); 69 | })} 70 |
71 |
72 |
73 |

Details

74 |

{description}

75 |
76 |
77 |

Info

78 |
price : Rs{price}
79 |
size : {size} SQFT
80 |
81 | max capacity :{" "} 82 | {capacity > 1 ? `${capacity} people` : `${capacity} person`} 83 |
84 |
{pets ? "pets allowed" : "no pets allowed"}
85 |
{breakfast && "free breakfast included"}
86 |
87 |
88 |
89 |
90 |

Extras

91 |
    92 | {extras.map((item, index) => { 93 | return
  • {item}
  • ; 94 | })} 95 |
96 |
97 |
98 |
99 | 105 |
106 |
107 | 111 | Update Room. 112 | 113 |
114 |
115 |
116 |
117 | 118 | ) : ( 119 |
120 |
121 |
122 |
123 |

SORRY

124 |

No such room could be found...

125 | 126 | Back to Rooms 127 | 128 |
129 |
130 |
131 |
132 | )} 133 | 134 | ); 135 | }; 136 | 137 | export default SingleRooms; 138 | -------------------------------------------------------------------------------- /src/images/notfound.svg: -------------------------------------------------------------------------------- 1 | not found -------------------------------------------------------------------------------- /src/Components/AddRooms.jsx: -------------------------------------------------------------------------------- 1 | import { ref, set } from "firebase/database"; 2 | import React, { useState } from "react"; 3 | import { db } from "../firebase"; 4 | import { v4 } from "uuid"; 5 | import { useNavigate } from "react-router-dom"; 6 | 7 | const AddRooms = () => { 8 | const navigate = useNavigate(); 9 | const uid = v4(); 10 | 11 | const [name, setName] = useState(""); 12 | const [type, settype] = useState(""); 13 | const [price, setprice] = useState(0); 14 | const [size, setsize] = useState(0); 15 | const [capacity, setcapacity] = useState(1); 16 | const [pets, setpets] = useState(false); 17 | const [breakfast, setbreakfast] = useState(false); 18 | const [description, setdescription] = useState(""); 19 | const [extras, setextras] = useState(""); 20 | const [image1, setImage1] = useState(""); 21 | const [image2, setImage2] = useState(""); 22 | const [image3, setImage3] = useState(""); 23 | const [image4, setImage4] = useState(""); 24 | 25 | const addRoomToFirebase = () => { 26 | if ( 27 | name && 28 | type && 29 | price && 30 | size && 31 | description && 32 | extras && 33 | image1 && 34 | image2 && 35 | image3 && 36 | image4 37 | ) { 38 | set(ref(db, `hotels/${uid}`), { 39 | sys: { 40 | id: uid, 41 | }, 42 | fields: { 43 | name, 44 | slug: uid.toString(), 45 | type, 46 | price, 47 | size, 48 | capacity, 49 | pets, 50 | breakfast, 51 | featured: false, 52 | description, 53 | extras: extras.split(","), 54 | images: [ 55 | { 56 | fields: { 57 | file: { 58 | url: image1, 59 | }, 60 | }, 61 | }, 62 | { 63 | fields: { 64 | file: { 65 | url: image2, 66 | }, 67 | }, 68 | }, 69 | { 70 | fields: { 71 | file: { 72 | url: image3, 73 | }, 74 | }, 75 | }, 76 | { 77 | fields: { 78 | file: { 79 | url: image4, 80 | }, 81 | }, 82 | }, 83 | ], 84 | }, 85 | }).then(() => { 86 | alert("Room Added!"); 87 | setName(""); 88 | settype(""); 89 | setcapacity(0); 90 | setdescription(""); 91 | setextras(""); 92 | setbreakfast(false); 93 | setpets(false); 94 | setprice(0); 95 | setsize(0); 96 | setImage1(""); 97 | setImage2(""); 98 | setImage3(""); 99 | setImage4(""); 100 | 101 | navigate("/rooms"); 102 | }); 103 | } else { 104 | return alert("Please fill all required fields."); 105 | } 106 | }; 107 | 108 | return ( 109 |
110 |
111 |
112 |
113 |

Add Room

114 |
115 | 116 |
117 |
118 |
119 |
120 |
121 | 122 | setName(e.target.value)} 127 | id="name" 128 | placeholder="Room name." 129 | required 130 | /> 131 | 132 | settype(e.target.value)} 137 | id="type" 138 | placeholder="Room type" 139 | required 140 | /> 141 | 142 | 143 | setprice(e.target.value)} 147 | className="form-control" 148 | required 149 | id="price" 150 | placeholder="Room price" 151 | /> 152 | 153 | setsize(e.target.value)} 158 | required 159 | id="size" 160 | placeholder="Room Size" 161 | /> 162 | 163 | setcapacity(e.target.value)} 167 | className="form-control" 168 | required 169 | id="capacity" 170 | placeholder="Capacitiy" 171 | /> 172 |
173 | setbreakfast(!breakfast)} 178 | name="breakfast" 179 | id="breakfast" 180 | /> 181 | 187 |
188 |
189 | setpets(!pets)} 195 | id="pets" 196 | /> 197 | 200 |
201 | 202 | 203 | 211 | 212 | 213 | 221 | 222 | 223 | setImage1(e.target.value)} 227 | className="form-control" 228 | id="img1" 229 | placeholder="Image 1 URL" 230 | required 231 | /> 232 | 233 | setImage2(e.target.value)} 238 | id="img2" 239 | placeholder="Image 2 URL" 240 | required 241 | /> 242 | 243 | 244 | setImage3(e.target.value)} 248 | className="form-control" 249 | id="img3" 250 | placeholder="Image 3 URL" 251 | required 252 | /> 253 | 254 | 255 | setImage4(e.target.value)} 259 | className="form-control" 260 | id="img4" 261 | placeholder="Image 4 URL" 262 | required 263 | /> 264 |
265 | 266 |
267 |
268 | 274 |
275 |
276 |
277 |
278 |
279 |
280 | ); 281 | }; 282 | 283 | export default AddRooms; 284 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Nunito&display=swap"); 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | font-family: "Nunito", sans-serif; 6 | } 7 | * { 8 | margin: 0; 9 | padding: 0; 10 | box-sizing: border-box; 11 | } 12 | :root { 13 | --primaryColor: #5656f1; 14 | --mainWhite: #fff; 15 | --offWhite: #f7f7f7; 16 | --mainBlack: #222; 17 | --mainGrey: #ececec; 18 | --darkGrey: #cfcfcf; 19 | --mainTransition: all 0.3s linear; 20 | --mainSpacing: 3px; 21 | --lightShadow: 2px 5px 3px 0px rgba(0, 0, 0, 0.5); 22 | --darkShadow: 4px 10px 5px 0px rgba(0, 0, 0, 0.5); 23 | } 24 | /* globals */ 25 | h1 { 26 | font-size: 3em; 27 | line-height: 1; 28 | margin-bottom: 0.5em; 29 | } 30 | h2 { 31 | font-size: 2em; 32 | margin-bottom: 0.75em; 33 | } 34 | h3 { 35 | font-size: 1.5em; 36 | line-height: 1; 37 | margin-bottom: 1em; 38 | } 39 | h4 { 40 | font-size: 1.2em; 41 | line-height: 1.25; 42 | margin-bottom: 1.25em; 43 | } 44 | h5 { 45 | font-size: 1em; 46 | font-weight: bold; 47 | margin-bottom: 1.5em; 48 | } 49 | h6 { 50 | font-size: 1em; 51 | font-weight: bold; 52 | margin-bottom: 1.5em; 53 | } 54 | 55 | .btn-primary { 56 | display: inline-block; 57 | text-decoration: none; 58 | letter-spacing: var(--mainSpacing); 59 | color: white; 60 | background: var(--primaryColor); 61 | padding: 0.4rem 0.9rem; 62 | border: 3px solid var(--primaryColor); 63 | transition: var(--mainTransition); 64 | text-transform: uppercase; 65 | cursor: pointer; 66 | } 67 | 68 | .phoneInput { 69 | margin-bottom: 10px; 70 | } 71 | label { 72 | margin-top: 10px; 73 | } 74 | 75 | .phoneInput input{ 76 | padding: 5px; 77 | border: 2px solid black; 78 | border-radius: 5px; 79 | } 80 | .btn-warning { 81 | display: inline-block; 82 | text-decoration: none; 83 | font-weight: bold; 84 | letter-spacing: var(--mainSpacing); 85 | color: white; 86 | background: var(--primaryColor); 87 | padding: 0.4rem 0.9rem; 88 | border: 3px solid var(--primaryColor); 89 | transition: var(--mainTransition); 90 | text-transform: uppercase; 91 | cursor: pointer; 92 | } 93 | .btn-primary:hover { 94 | text-decoration: none; 95 | border: 3px solid var(--primaryColor); 96 | background: rgba(0, 0, 0, 0.5) !important; 97 | color: #fff !important; 98 | } 99 | .btn-warning:hover { 100 | text-decoration: none; 101 | background: transparent !important; 102 | color: yellow !important; 103 | } 104 | .loading { 105 | text-transform: capitalize; 106 | margin: 0px auto; 107 | text-align: center; 108 | margin-top: 3rem; 109 | } 110 | .roomerror { 111 | margin-top: 100px; 112 | } 113 | .roomerror:hover .error { 114 | background-color: #2c3e50; 115 | color: #ffffff !important; 116 | } 117 | .error { 118 | text-align: center; 119 | text-transform: uppercase; 120 | margin: 2rem 0; 121 | } 122 | .empty-search { 123 | text-align: center; 124 | text-transform: capitalize; 125 | margin: 2rem 0; 126 | padding: 1rem; 127 | letter-spacing: var(--mainSpacing); 128 | } 129 | 130 | /* end of globals */ 131 | /* Navbar */ 132 | .nav-link { 133 | padding: 8px 15px; 134 | margin-left: 10px; 135 | margin-right: 20px; 136 | font-size: 18px; 137 | text-align: center; 138 | border: 2px solid transparent; 139 | transition: 0.5s linear; 140 | font-weight: 800; 141 | -webkit-transition: 0.5s linear; 142 | -moz-transition: 0.5s linear; 143 | -ms-transition: 0.5s linear; 144 | -o-transition: 0.5s linear; 145 | } 146 | .bg-transparent.scrolled { 147 | background-color: black !important; 148 | transition: 500ms ease; 149 | } 150 | 151 | .navbar-brand { 152 | font-size: 32px !important; 153 | color: #ffffff !important; 154 | } 155 | .nav-link:hover { 156 | color: white; 157 | transform: scale(1.1); 158 | } 159 | .nav-link.active_class { 160 | color: #ffffff; 161 | border: 2px solid #ffffff; 162 | font-weight: 800; 163 | } 164 | 165 | .form-control { 166 | border: 2px solid #000; 167 | } 168 | .form-control:focus, 169 | .form-control.active { 170 | border: 2px solid #000000 !important; 171 | } 172 | textarea:focus, 173 | textarea.form-control:focus, 174 | input.form-control:focus, 175 | input[type="text"]:focus, 176 | input[type="password"]:focus, 177 | input[type="email"]:focus, 178 | input[type="number"]:focus, 179 | [type="text"].form-control:focus, 180 | [type="password"].form-control:focus, 181 | [type="email"].form-control:focus, 182 | [type="tel"].form-control:focus, 183 | [contenteditable].form-control:focus { 184 | box-shadow: inset 0 -1px 0 #ddd; 185 | } 186 | 187 | /* end of navbar */ 188 | /* Hero */ 189 | .defaultHero, 190 | .roomsHero { 191 | min-height: calc(100vh - 0px); 192 | background: url("https://vistapointe.net/images/hotel-1.jpg") 193 | center/cover no-repeat; 194 | display: flex; 195 | align-items: center; 196 | justify-content: center; 197 | position: relative; 198 | } 199 | .roomsHero { 200 | background-image: url("https://www.berjayahotel.com/sites/default/files/colombo_30.jpg"); 201 | min-height: calc(100vh - 0px); 202 | } 203 | 204 | .lost { 205 | font-size: 44px; 206 | color: yellow; 207 | text-align: center; 208 | } 209 | /* End of Hero */ 210 | /* Banner */ 211 | .banner { 212 | display: inline-block; 213 | position: absolute !important; 214 | background: rgba(0, 0, 0, 0.5) !important; 215 | color: var(--mainWhite); 216 | text-align: center; 217 | text-transform: capitalize; 218 | letter-spacing: var(--mainSpacing); 219 | top: 50%; 220 | left: 50%; 221 | transform: translate(-50%, -50%); 222 | } 223 | .banner h1 { 224 | font-size: 44px !important; 225 | } 226 | .banner div { 227 | width: 10rem; 228 | height: 5px; 229 | background: var(--primaryColor); 230 | margin: 1.7rem auto; 231 | } 232 | .banner p { 233 | font-size: 1.2rem; 234 | margin-bottom: 2rem; 235 | } 236 | @media screen and (max-width: 576px) { 237 | .banner { 238 | padding: 2rem 3rem !important; 239 | } 240 | .banner h1 { 241 | font-size: 32px !important; 242 | } 243 | } 244 | @media screen and (min-width: 992px) { 245 | .banner { 246 | padding: 2rem 6rem; 247 | } 248 | .banner h1 { 249 | font-size: 4rem; 250 | } 251 | } 252 | /* End of Banner */ 253 | /* Title */ 254 | .section-title { 255 | text-align: center; 256 | margin-bottom: 4rem; 257 | } 258 | .section-title h4 { 259 | font-size: 2rem; 260 | letter-spacing: var(--mainSpacing); 261 | text-transform: capitalize; 262 | margin-bottom: 1rem; 263 | } 264 | .section-title div { 265 | width: 5rem; 266 | height: 5px; 267 | margin: 0 auto; 268 | background: var(--primaryColor); 269 | } 270 | /* end of Title */ 271 | 272 | /* services */ 273 | .services { 274 | padding: 3rem 0; 275 | } 276 | .services { 277 | background: #ebf5fb; 278 | text-align: center; 279 | } 280 | 281 | .service span { 282 | display: inline-block; 283 | color: var(--primaryColor); 284 | font-size: 80px; 285 | margin-bottom: 1.5rem; 286 | transition: 1s linear; 287 | -webkit-transition: 1s linear; 288 | -moz-transition: 1s linear; 289 | -ms-transition: 1s linear; 290 | -o-transition: 1s linear; 291 | } 292 | .services span:hover { 293 | transform: rotate(360deg); 294 | -webkit-transform: rotate(360deg); 295 | -moz-transform: rotate(360deg); 296 | -ms-transform: rotate(360deg); 297 | -o-transform: rotate(360deg); 298 | } 299 | .services h6 { 300 | letter-spacing: var(--mainSpacing); 301 | font-weight: 1000; 302 | text-transform: capitalize; 303 | } 304 | .services p { 305 | width: 80%; 306 | margin: 0 auto; 307 | } 308 | @media screen and (min-width: 992px) { 309 | .services-center { 310 | width: 95vw; 311 | max-width: 1170px; 312 | } 313 | } 314 | 315 | @media screen and (min-width: 1200px) { 316 | .services p { 317 | width: 100%; 318 | } 319 | } 320 | /*end of services */ 321 | /* featured rooms */ 322 | 323 | .featured-rooms { 324 | padding: 5rem 0; 325 | } 326 | 327 | /* end pf featured rooms */ 328 | /* room */ 329 | .room { 330 | transition: 0.4s linear; 331 | -webkit-transition: 0.4s linear; 332 | -moz-transition: 0.4s linear; 333 | -ms-transition: 0.4s linear; 334 | -o-transition: 0.4s linear; 335 | position: relative; 336 | } 337 | .room:hover { 338 | box-shadow: 0px 9px 18px rgba(0, 0, 0, 0.5) !important; 339 | } 340 | 341 | .price-top { 342 | position: absolute; 343 | top: 0; 344 | left: 0; 345 | background: rgba(0, 0, 0, 0.8); 346 | color: var(--mainWhite); 347 | padding: 0.3rem 0.6rem 0.5rem; 348 | border-bottom-right-radius: 1rem; 349 | font-size: 0.5rem; 350 | text-align: center; 351 | transition: 0.4s linear; 352 | -webkit-transition: 0.4s linear; 353 | -moz-transition: 0.4s linear; 354 | -ms-transition: 0.4s linear; 355 | -o-transition: 0.4s linear; 356 | } 357 | .price-top h6 { 358 | margin-bottom: 0; 359 | font-size: 0.9rem; 360 | font-weight: 300; 361 | letter-spacing: var(--mainSpacing); 362 | } 363 | .room-link { 364 | position: absolute; 365 | bottom: 0; 366 | right: 0; 367 | opacity: 0; 368 | color: white; 369 | transition: all 0.3s linear; 370 | } 371 | .room:hover { 372 | background: rgba(0, 0, 0, 0.8); 373 | } 374 | .room:hover img { 375 | opacity: 0.3; 376 | } 377 | .room:hover .price-top { 378 | opacity: 0; 379 | } 380 | .room:hover .room-link { 381 | opacity: 1; 382 | color: white; 383 | transform: translate(-100%, -180%) scale(1); 384 | -webkit-transform: translate(-60%, -260%) scale(1); 385 | -moz-transform: translate(-50%, -200%) scale(1); 386 | -ms-transform: translate(-50%, -200%) scale(1); 387 | -o-transform: translate(-50%, -200%) scale(1); 388 | } 389 | .room-info { 390 | background: #f2f3f4; 391 | text-transform: capitalize; 392 | padding: 0.5rem 0; 393 | text-align: center; 394 | font-weight: 700; 395 | letter-spacing: var(--mainSpacing); 396 | margin-bottom: 0; 397 | } 398 | /* end of room */ 399 | /* single room*/ 400 | 401 | .single-room { 402 | padding: 5rem 0 0 0; 403 | } 404 | .single-room-images { 405 | width: 80vw; 406 | margin: 0 auto; 407 | display: grid; 408 | grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); 409 | grid-row-gap: 2rem; 410 | grid-column-gap: 50px; 411 | } 412 | .single-room-images img { 413 | width: 100%; 414 | display: block; 415 | } 416 | .single-room-info { 417 | width: 80vw; 418 | display: grid; 419 | grid-template-columns: 1fr; 420 | margin: 2rem auto; 421 | } 422 | .desc, 423 | .info { 424 | margin: 1rem 0; 425 | } 426 | .desc h3 { 427 | text-transform: capitalize; 428 | letter-spacing: var(--mainSpacing); 429 | } 430 | .desc p { 431 | line-height: 1.5; 432 | } 433 | .info h3, 434 | .info h6 { 435 | text-transform: capitalize; 436 | letter-spacing: var(--mainSpacing); 437 | } 438 | 439 | .info h6 { 440 | font-weight: 300; 441 | } 442 | .room-extras { 443 | width: 80vw; 444 | margin: 0 auto 3rem auto; 445 | } 446 | .room-extras h6 { 447 | text-transform: capitalize; 448 | letter-spacing: var(--mainSpacing); 449 | } 450 | .extras { 451 | list-style-type: none; 452 | display: grid; 453 | grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); 454 | grid-column-gap: 2rem; 455 | grid-row-gap: 1rem; 456 | } 457 | @media screen and (min-width: 992px) { 458 | .single-room-images, 459 | .single-room-info, 460 | .room-extras { 461 | width: 95vw; 462 | max-width: 1170px; 463 | } 464 | .single-room-info { 465 | display: grid; 466 | grid-template-columns: 1fr 1fr; 467 | grid-column-gap: 2rem; 468 | } 469 | .info { 470 | padding-left: 3rem; 471 | } 472 | } 473 | /* end of single room*/ 474 | /* roomlist */ 475 | .roomslist { 476 | padding: 5rem 0; 477 | } 478 | .roomslist-center { 479 | width: 80vw; 480 | margin: 0 auto; 481 | display: grid; 482 | grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); 483 | grid-row-gap: 2rem; 484 | grid-column-gap: 30px; 485 | } 486 | 487 | @media screen and (min-width: 776px) { 488 | .roomslist-center { 489 | width: 90vw; 490 | } 491 | } 492 | @media screen and (min-width: 992px) { 493 | .roomslist-center { 494 | width: 95vw; 495 | max-width: 1170px; 496 | } 497 | } 498 | /* end of roomlist */ 499 | /* rooms fitler*/ 500 | /* .filter-container { 501 | padding: 5rem 0; 502 | } 503 | 504 | .form-group { 505 | text-transform: capitalize; 506 | } 507 | .form-group label { 508 | display: block; 509 | letter-spacing: var(--mainSpacing); 510 | margin-bottom: 0.5rem; 511 | } */ 512 | 513 | .single-extra label { 514 | display: inline-block; 515 | font-size: 0.8rem; 516 | margin-left: 0.5rem; 517 | } 518 | 519 | /* end of rooms fitler*/ 520 | 521 | /* aboutus */ 522 | 523 | .aboutus, 524 | .contact { 525 | margin-top: 100px !important; 526 | } 527 | .about_company, 528 | .team { 529 | padding: 60px 30px; 530 | } 531 | .about_info { 532 | letter-spacing: 40; 533 | } 534 | .carousel-inner { 535 | min-height: 400px !important; 536 | max-height: 400px !important; 537 | } 538 | .connect { 539 | font-size: 44px !important; 540 | padding: 5px 8px; 541 | } 542 | /* end of about us */ 543 | -------------------------------------------------------------------------------- /src/Components/updateRoom.jsx: -------------------------------------------------------------------------------- 1 | import { ref, update } from "firebase/database"; 2 | import React, { useEffect, useState } from "react"; 3 | import { useSelector } from "react-redux"; 4 | import { db } from "../firebase"; 5 | import { v4 } from "uuid"; 6 | import { Link, useNavigate, useParams } from "react-router-dom"; 7 | 8 | const UpdateRoom = () => { 9 | const { slug } = useParams(); 10 | const state = useSelector((state) => state); 11 | const navigate = useNavigate(); 12 | const uid = v4(); 13 | 14 | const [name, setName] = useState(""); 15 | const [type, settype] = useState(""); 16 | const [price, setprice] = useState(0); 17 | const [size, setsize] = useState(0); 18 | const [capacity, setcapacity] = useState(1); 19 | const [pets, setpets] = useState(false); 20 | const [breakfast, setbreakfast] = useState(false); 21 | const [description, setdescription] = useState(""); 22 | const [extras, setextras] = useState(""); 23 | const [image1, setImage1] = useState(""); 24 | const [image2, setImage2] = useState(""); 25 | const [image3, setImage3] = useState(""); 26 | const [image4, setImage4] = useState(""); 27 | 28 | function getRoom(arg) { 29 | 30 | const idiRooms = state[0][0].rooms.map((item) => item); 31 | const roomDatas = idiRooms.filter((roomItem) => roomItem.slug === arg); 32 | return roomDatas; 33 | } 34 | 35 | if (state.length > 0 && slug) { 36 | const roomData = getRoom(slug); 37 | console.log(roomData); 38 | if (roomData.length > 0) { 39 | var id = roomData[0].id; 40 | var newtype = roomData[0].type; 41 | var newname = roomData[0].name; 42 | var newdescription = roomData[0].description; 43 | var newcapacity = roomData[0].capacity; 44 | var newsize = roomData[0].size; 45 | var newprice = roomData[0].price; 46 | var newextras = roomData[0].extras; 47 | var newbreakfast = roomData[0].breakfast; 48 | var newpets = roomData[0].pets; 49 | const images = roomData[0].images; 50 | var img1 = images[0]; 51 | var img2 = images[1]; 52 | var img3 = images[2]; 53 | var img4 = images[3]; 54 | } 55 | } 56 | 57 | useEffect(() => { 58 | setName(newname || ""); 59 | setcapacity(newcapacity); 60 | settype(newtype); 61 | setdescription(newdescription); 62 | setprice(newprice); 63 | setsize(newsize); 64 | setextras(newextras && newextras.toString()); 65 | setbreakfast(newbreakfast); 66 | setpets(newpets); 67 | setImage1(img1); 68 | setImage2(img2); 69 | setImage3(img3); 70 | setImage4(img4); 71 | console.log(name); 72 | // eslint-disable-next-line react-hooks/exhaustive-deps 73 | }, []); 74 | 75 | async function updateRoomFirebase() { 76 | if ( 77 | name && 78 | type && 79 | price && 80 | size && 81 | description && 82 | extras && 83 | image1 && 84 | image2 && 85 | image3 && 86 | image4 87 | ) { 88 | await update(ref(db, `hotels/${id}`), { 89 | sys: { 90 | id, 91 | }, 92 | fields: { 93 | name, 94 | slug: uid.toString(), 95 | type: newtype, 96 | price, 97 | size, 98 | capacity, 99 | pets, 100 | breakfast, 101 | featured: false, 102 | description: description, 103 | extras: extras.split(","), 104 | images: [ 105 | { 106 | fields: { 107 | file: { 108 | url: image1, 109 | }, 110 | }, 111 | }, 112 | { 113 | fields: { 114 | file: { 115 | url: image2, 116 | }, 117 | }, 118 | }, 119 | { 120 | fields: { 121 | file: { 122 | url: image3, 123 | }, 124 | }, 125 | }, 126 | { 127 | fields: { 128 | file: { 129 | url: image4, 130 | }, 131 | }, 132 | }, 133 | ], 134 | }, 135 | }).then(() => { 136 | alert("Room updated.!"); 137 | setName(""); 138 | settype(""); 139 | setcapacity(0); 140 | setdescription(""); 141 | setextras(""); 142 | setbreakfast(false); 143 | setpets(false); 144 | setprice(0); 145 | setsize(0); 146 | setImage1(""); 147 | setImage2(""); 148 | setImage3(""); 149 | setImage4(""); 150 | 151 | navigate(`/rooms`); 152 | }); 153 | } else { 154 | return alert("Please fill all required fields."); 155 | } 156 | } 157 | 158 | return ( 159 | <> 160 | {slug ? ( 161 |
162 |
163 |
164 |
165 |

Update Room

166 |
167 | 168 |
169 |
170 |
171 |
172 |
173 | 174 | setName(e.target.value)} 179 | id="name" 180 | placeholder="Room name." 181 | required 182 | /> 183 | 184 | 185 | setprice(e.target.value)} 189 | className="form-control" 190 | required 191 | id="price" 192 | placeholder="Room price" 193 | /> 194 | 195 | setsize(e.target.value)} 200 | required 201 | id="size" 202 | placeholder="Room Size" 203 | /> 204 | 205 | setcapacity(e.target.value)} 209 | className="form-control" 210 | required 211 | id="capacity" 212 | placeholder="Capacitiy" 213 | /> 214 |
215 | setbreakfast(!breakfast)} 220 | name="breakfast" 221 | id="breakfast" 222 | /> 223 | 229 |
230 |
231 | setpets(!pets)} 237 | id="pets" 238 | /> 239 | 245 |
246 | 247 | 248 | 256 | 257 | 258 | 266 | 267 | 268 | setImage1(e.target.value)} 272 | className="form-control" 273 | id="img1" 274 | placeholder="Image 1 URL" 275 | required 276 | /> 277 | 278 | setImage2(e.target.value)} 283 | id="img2" 284 | placeholder="Image 2 URL" 285 | required 286 | /> 287 | 288 | 289 | setImage3(e.target.value)} 293 | className="form-control" 294 | id="img3" 295 | placeholder="Image 3 URL" 296 | required 297 | /> 298 | 299 | 300 | setImage4(e.target.value)} 304 | className="form-control" 305 | id="img4" 306 | placeholder="Image 4 URL" 307 | required 308 | /> 309 |
310 | 311 |
312 |
313 | 319 |
320 |
321 |
322 |
323 |
324 |
325 | ) : ( 326 | <> 327 |
328 |
329 |
330 |
331 |

Update

332 |

Please select room from Room page..

333 | 334 | Back to Rooms 335 | 336 |
337 |
338 |
339 |
340 | 341 | )} 342 | 343 | ); 344 | }; 345 | 346 | export default UpdateRoom; 347 | --------------------------------------------------------------------------------