diff --git a/package-lock.json b/package-lock.json index 8197e6f22..8e973868b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,10 @@ "name": "react-hotel", "version": "0.1.0", "dependencies": { + "moment": "^2.29.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.22.1", "react-scripts": "^5.0.1" }, "devDependencies": { @@ -3056,6 +3058,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@remix-run/router": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.1.tgz", + "integrity": "sha512-zcU0gM3z+3iqj8UX45AmWY810l3oUmXM7uH4dt5xtzvMhRtYVhKGOmgOd1877dOPPepfCjUv57w+syamWIYe7w==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -11681,6 +11691,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -14054,6 +14072,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.1.tgz", + "integrity": "sha512-0pdoRGwLtemnJqn1K0XHUbnKiX0S4X8CgvVVmHGOWmofESj31msHo/1YiqcJWK7Wxfq2a4uvvtS01KAQyWK/CQ==", + "dependencies": { + "@remix-run/router": "1.15.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.22.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.1.tgz", + "integrity": "sha512-iwMyyyrbL7zkKY7MRjOVRy+TMnS/OPusaFVxM2P11x9dzSzGmLsebkCvYirGq0DWB9K9hOspHYYtDz33gE5Duw==", + "dependencies": { + "@remix-run/router": "1.15.1", + "react-router": "6.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", diff --git a/package.json b/package.json index e3e1562a7..d38148e75 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,10 @@ "version": "0.1.0", "private": true, "dependencies": { + "moment": "^2.29.4", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.22.1", "react-scripts": "^5.0.1" }, "scripts": { diff --git a/public/.index.html.icloud b/public/.index.html.icloud new file mode 100644 index 000000000..55648e149 Binary files /dev/null and b/public/.index.html.icloud differ diff --git a/src/.App.css.icloud b/src/.App.css.icloud new file mode 100644 index 000000000..b895cba05 Binary files /dev/null and b/src/.App.css.icloud differ diff --git a/src/App.css b/src/App.css index 05fe2d52e..0b4b53def 100644 --- a/src/App.css +++ b/src/App.css @@ -1,57 +1,68 @@ -.App { - text-align: left; +.btn-custom { + background-color: #ff7f50; + /* Custom color */ + border-color: #ff7f50; + /* Custom border color */ + transition: background-color 0.3s, border-color 0.3s; + /* Smooth transition on hover */ } -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 80px; +.btn-custom:hover { + background-color: #ff6347; + /* Darker shade on hover */ + border-color: #ff6347; + /* Darker shade on hover */ } -.App-header { - background-color: #222; - height: 50px; - padding: 20px; - color: white; - text-align: left; - font-family: Arial, Helvetica, sans-serif; - font-size: 1em; - font-weight: bold; +.service-card { + transition: all 0.3s ease; + /* Apply transition effect to all properties */ } -.App-title { - font-size: 1.5em; +.service-card:hover { + transform: scale(1.05); + /* Grow the card slightly on hover */ + background-color: #f8f9fa; + /* Change background color on hover */ } -.App-content { - padding-top: 20px; - font-size: large; +/* Bookings.css */ +.loading-container { + display: flex; + flex-direction: column; + align-items: center; } -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} -.search { - padding: 5px 0 20px 0; +.blink_me { + font-size: 24px; + color: #333; + text-transform: uppercase; + letter-spacing: 2px; + animation: blink 1s infinite alternate; } -tr { - color: #5b5757; -} +@keyframes blink { + 0% { + opacity: 0.2; + } -.results { - padding-top: 15px; + 100% { + opacity: 1; + } } -.footer { - padding-top: 20px; - text-align: center; +.loading-spinner { + border: 4px solid rgba(0, 0, 0, 0.1); + border-left-color: #333; + border-radius: 50%; + width: 40px; + height: 40px; + animation: spin 1s linear infinite; + margin-top: 20px; } -.card { - width: 18rem; -} +@keyframes spin { + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 953c98560..bcb7d9a87 100644 --- a/src/App.js +++ b/src/App.js @@ -1,13 +1,23 @@ import React from "react"; - -import Bookings from "./Bookings"; +import Bookings from "./Components/Bookings"; import "./App.css"; +import Heading from "./Components/Heading"; +import Footer from "./Components/Footer"; +import TouristInfoCards from "./Components/TouristInfoCards"; +import Restaurant from "./Components/Restaurant"; +import HotelServices from "./Components/HotelServices"; +import RoomTypes from "./Components/RoomTypes"; const App = () => { return (
-
CYF Hotel
+ + + + + +
); }; diff --git a/src/Bookings.js b/src/Bookings.js deleted file mode 100644 index e0d911b13..000000000 --- a/src/Bookings.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from "react"; -import Search from "./Search.js"; -// import SearchResults from "./SearchResults.js"; -// import FakeBookings from "./data/fakeBookings.json"; - -const Bookings = () => { - const search = searchVal => { - console.info("TO DO!", searchVal); - }; - - return ( -
-
- - {/* */} -
-
- ); -}; - -export default Bookings; diff --git a/src/Components/Bookings.js b/src/Components/Bookings.js new file mode 100644 index 000000000..f56b13343 --- /dev/null +++ b/src/Components/Bookings.js @@ -0,0 +1,61 @@ +import React, { useState, useEffect } from "react"; +import Search from "./Search.js"; +import SearchResults from "./SearchResults.js"; +// import FakeBookings from "./data/fakeBookings.json"; + +const Bookings = () => { + const [bookings, setBookings] = useState([]); + const [loadingData, setLoadingData] = useState(false); + const [errorMsg, setErrorMsg] = useState(null); + useEffect(() => { + setLoadingData(false); + fetch(`https://andrius-hotel-server.onrender.com/bookings`) + .then((res) => { + if (!res.ok) { + throw Error( + `The fetching of bookings was not successful. Error: ${res.status}` + ); + } + return res.json(); + }) + .then((data) => { + setBookings(data); + setLoadingData(true); + setErrorMsg(null); + }) + .catch((error) => { + setErrorMsg(error.message); + }); + }, []); + const search = (searchVal) => { + const filteredBooking = bookings.filter((booking) => { + return ( + booking.firstName.toLowerCase().includes(searchVal.toLowerCase()) || + booking.surname.toLowerCase().includes(searchVal.toLowerCase()) + ); + }); + + setBookings(filteredBooking); + // console.info("TO DO!", searchVal); + }; + + return ( +
+
+ {/* */} + {errorMsg ? ( +

{errorMsg}

+ ) : loadingData ? ( + + ) : ( +
+

Loading.....

+
+
+ )} +
+
+ ); +}; + +export default Bookings; diff --git a/src/Components/CustomerProfile.js b/src/Components/CustomerProfile.js new file mode 100644 index 000000000..bd462848b --- /dev/null +++ b/src/Components/CustomerProfile.js @@ -0,0 +1,52 @@ +import React, { useEffect, useState } from "react"; + +const CustomerProfile = (props) => { + const [customerData, setCustomerData] = useState(null); // Initialize customerData as null + + useEffect(() => { + if (props.id) { + fetch(`https://andrius-hotel-server.onrender.com/bookings/${props.id}`) + .then((response) => response.json()) + .then((data) => setCustomerData(data)) + .catch((error) => + console.error("Error fetching customer data:", error) + ); + } + }, [props.id]); + + if (!customerData) { + return

Loading...

; // Display loading message while fetching data + } + + // Assuming customerData is an array + const customer = customerData[0]; // Assuming the data for the customer is at the first index of the array + + return ( + + + + + + + + + + + + + + + + + + + + + + + +
Customer IDTitleFirst NameSurnameEmailVIPPhone number
{props.id}{customer.title}{customer.firstName}{customer.surname}{customer.email}{customer.vip ? "Yes" : "No"}{customer.phoneNumber}
+ ); +}; + +export default CustomerProfile; diff --git a/src/Components/Footer.js b/src/Components/Footer.js new file mode 100644 index 000000000..c8f447ac6 --- /dev/null +++ b/src/Components/Footer.js @@ -0,0 +1,67 @@ +import React from "react"; + +const ContactDetails = [ + "123 Fake Street, London, E1 4UD", + "hello@fakehotel.com", + "0123 456789", +]; + +const Footer = () => { + return ( + + ); +}; + +export default Footer; diff --git a/src/Components/Heading.js b/src/Components/Heading.js new file mode 100644 index 000000000..9adc6fdc2 --- /dev/null +++ b/src/Components/Heading.js @@ -0,0 +1,62 @@ +import React from "react"; + +const Navbar = () => { + return ( + + ); +}; + +export default Navbar; diff --git a/src/Components/HotelServices.js b/src/Components/HotelServices.js new file mode 100644 index 000000000..0db93859d --- /dev/null +++ b/src/Components/HotelServices.js @@ -0,0 +1,49 @@ +import React from "react"; + +const HotelServices = () => { + return ( +
+

Our Services

+
+
+
+
+ +
Free Wi-Fi
+

+ Stay connected with our high-speed Wi-Fi available throughout + the hotel. +

+
+
+
+
+
+
+ +
Poolside Lounge
+

+ Relax and unwind by our poolside lounge area with refreshing + drinks and snacks. +

+
+
+
+
+
+
+ +
Concierge Service
+

+ Our dedicated concierge team is available 24/7 to assist you + with all your needs. +

+
+
+
+
+
+ ); +}; + +export default HotelServices; diff --git a/src/Components/Order.js b/src/Components/Order.js new file mode 100644 index 000000000..c84e76295 --- /dev/null +++ b/src/Components/Order.js @@ -0,0 +1,18 @@ +import React, { useState } from "react"; +import RestaurantButton from "./RestaurantButton"; +const Order = (props) => { + const [order, setOrders] = useState(0); + const orderOne = () => { + setOrders(order + 1); + }; + return ( +
  • +

    + {props.orderType}: {order} +

    + +
  • + ); +}; + +export default Order; diff --git a/src/Components/Restaurant.js b/src/Components/Restaurant.js new file mode 100644 index 000000000..718a24d6b --- /dev/null +++ b/src/Components/Restaurant.js @@ -0,0 +1,16 @@ +import React from "react"; +import Order from "./Order"; +const Restaurant = () => { + return ( +
    +

    Restaurant Orders

    + +
    + ); +}; + +export default Restaurant; diff --git a/src/Components/RestaurantButton.js b/src/Components/RestaurantButton.js new file mode 100644 index 000000000..3dc209978 --- /dev/null +++ b/src/Components/RestaurantButton.js @@ -0,0 +1,8 @@ +const RestaurantButton = (props) => { + return ( + + ); +}; +export default RestaurantButton; diff --git a/src/Components/RoomTypes.js b/src/Components/RoomTypes.js new file mode 100644 index 000000000..f1daf3eed --- /dev/null +++ b/src/Components/RoomTypes.js @@ -0,0 +1,61 @@ +import React from "react"; + +const RoomTypes = () => { + return ( +
    +

    Our Rooms

    +
    +
    +
    + Standard Room +
    +
    Standard Room
    +

    + Comfortable and spacious room equipped with all the necessary + amenities for a pleasant stay. +

    +
    +
    +
    +
    +
    + Deluxe Room +
    +
    Deluxe Room
    +

    + Luxurious room with additional amenities and elegant decor for a + truly indulgent experience. +

    +
    +
    +
    +
    +
    + Suite +
    +
    Suite
    +

    + Spacious suite with separate living and sleeping areas, perfect + for families or extended stays. +

    +
    +
    +
    +
    +
    + ); +}; + +export default RoomTypes; diff --git a/src/Search.js b/src/Components/Search.js similarity index 54% rename from src/Search.js rename to src/Components/Search.js index 7bd5871c0..9aad06c6e 100644 --- a/src/Search.js +++ b/src/Components/Search.js @@ -1,6 +1,14 @@ -import React from "react"; - -const Search = () => { +import React, { useState } from "react"; +import SearchButton from "./SearchButton"; +const Search = (props) => { + const [searchInput, setSearchInput] = useState(""); + const handleSearchInput = (event) => { + setSearchInput(event.target.value); + }; + const handleSubmit = (event) => { + event.preventDefault(); + props.search(searchInput); + }; return (
    @@ -8,16 +16,17 @@ const Search = () => {
    -
    +
    -
    diff --git a/src/Components/SearchButton.js b/src/Components/SearchButton.js new file mode 100644 index 000000000..4cc9d047d --- /dev/null +++ b/src/Components/SearchButton.js @@ -0,0 +1,5 @@ +const SearchButton = (props) => { + return ; +}; + +export default SearchButton; diff --git a/src/Components/SearchResults.js b/src/Components/SearchResults.js new file mode 100644 index 000000000..455f1f4f3 --- /dev/null +++ b/src/Components/SearchResults.js @@ -0,0 +1,28 @@ +import { useState } from "react"; +import TableHead from "./TableHead.js"; +import TableInfo from "./TableInfo"; +import CustomerProfile from "./CustomerProfile"; +import Table from "./Table.js"; + +const SearchResults = (props) => { + const [showId, setShowId] = useState(""); + const IdCheck = (id) => { + setShowId(id); + console.log({ showId }); + }; + return ( + <> + + {/* {showId && } +
    + + + {props.results.map((result, id) => { + return ; + })} + +
    */} + + ); +}; +export default SearchResults; diff --git a/src/Components/Table.js b/src/Components/Table.js new file mode 100644 index 000000000..02d4fef2a --- /dev/null +++ b/src/Components/Table.js @@ -0,0 +1,67 @@ +import React, { useState } from "react"; +import moment from "moment"; +import CustomerProfile from "./CustomerProfile"; + +const Table = ({ results }) => { + const [showId, setShowId] = useState(null); + + const IdCheck = (id) => { + setShowId(showId === id ? null : id); + }; + + return ( +
    + + + + + + + + + + + + + + + + + {results.map((result) => ( + + + + + + + + + + + + + ))} + +
    idTitleFirst nameSurnameEmailRoom idCheck in dateCheck out dateNumber of nightsActions
    {result.id}{result.title}{result.firstName}{result.surname}{result.email}{result.roomId}{result.checkInDate}{result.checkOutDate} + {moment(result.checkOutDate).diff(result.checkInDate, "days")} + + +
    + {showId && ( +
    + + +
    + )} +
    + ); +}; + +export default Table; diff --git a/src/Components/TableBody.js b/src/Components/TableBody.js new file mode 100644 index 000000000..0fe9d88a6 --- /dev/null +++ b/src/Components/TableBody.js @@ -0,0 +1,24 @@ +import { useState } from "react"; +import TableInfo from "./TableInfo"; +import CustomerProfile from "./CustomerProfile"; + +const TableBody = (props) => { + const [showId, setShowId] = useState(""); + const IdCheck = (id) => { + setShowId(id); + console.log({ showId }); + }; + return ( + <> + + + {props.results.map((result, id) => { + return ; + })} + +
    + {showId && } + + ); +}; +export default TableBody; diff --git a/src/Components/TableHead.js b/src/Components/TableHead.js new file mode 100644 index 000000000..3a79cabd2 --- /dev/null +++ b/src/Components/TableHead.js @@ -0,0 +1,18 @@ +const TableHead = () => { + return ( + + + id + Title + First name + Surname + Email + Room id + Check in date + Check out date + Number of nights + + + ); +}; +export default TableHead; diff --git a/src/Components/TableInfo.js b/src/Components/TableInfo.js new file mode 100644 index 000000000..44c22bba5 --- /dev/null +++ b/src/Components/TableInfo.js @@ -0,0 +1,50 @@ +import { useState } from "react"; +import moment from "moment"; +const TableInfo = (props) => { + const [active, setActive] = useState(false); + + function handleClick() { + setActive(!active); + } + + return ( + <> + + {props.result.id} + {props.result.title} + {props.result.firstName} + {props.result.surname} + {props.result.email} + {props.result.roomId} + {props.result.checkInDate} + {props.result.checkOutDate} + + {moment(props.result.checkOutDate).diff( + props.result.checkInDate, + "days" + )} + + + {/* */} + + + + + + + ); +}; +export default TableInfo; diff --git a/src/Components/TouristInfoCards.js b/src/Components/TouristInfoCards.js new file mode 100644 index 000000000..8bc235d68 --- /dev/null +++ b/src/Components/TouristInfoCards.js @@ -0,0 +1,58 @@ +import React from "react"; + +const TouristInfo = [ + { + title: "Glasgow", + image: "https://media.timeout.com/images/105400989/1920/1080/image.jpg", + info: "Glasgow's city centre is home to flagship stores, impressive shopping centres and designer favourites all within an easily walkable area. The city is also rich in artists and creators which makes for a thriving and exciting independent shopping scene.", + link: "https://peoplemakeglasgow.com", + }, + { + title: "Manchester", + image: + "https://www.propertyreporter.co.uk/images/660x350/manchester_895-14609.jpg", + info: "Welcome to the official tourism site of Greater Manchester where you can search for things to do in Manchester and find out what's on, as well as getting inspiration for your visit to this fantastic city region.", + link: "https://visitmanchester.com", + }, + { + title: "London", + image: + "https://www.citysparespace.com/wp-content/uploads/2023/02/london.jpeg", + info: "Welcome to London! Discover the best of London with Visit London, the official guide to England’s exciting capital. Find things to do in London, from iconic sightseeing spots and fun-filled days out to top restaurants, theatre and unmissable London events. If you’re not able to visit just yet, plan ahead to make the most of your next visit.", + link: "https://visitlondon.com", + }, +]; + +const TouristInfoCards = () => { + return ( +
    +
    + {TouristInfo.map((card, id) => { + return ( +
    +
    + {card.title} +
    +

    {card.title}

    +

    {card.info}

    + + More Information + +
    +
    +
    + ); + })} +
    +
    + ); +}; + +export default TouristInfoCards; diff --git a/src/Restaurant.js b/src/Restaurant.js deleted file mode 100644 index ecb2b43a2..000000000 --- a/src/Restaurant.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from "react"; - -const Restaurant = () => { - const pizzas = 0; - return ( -
    -

    Restaurant Orders

    -
      -
    • - Pizzas: {pizzas} -
    • -
    -
    - ); -}; - -export default Restaurant;