diff --git a/package-lock.json b/package-lock.json index 8197e6f22..71fa131f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,16 @@ "name": "react-hotel", "version": "0.1.0", "dependencies": { + "eslint": "^8.35.0", + "moment": "^2.29.4", "react": "^18.2.0", + "react-datepicker": "^4.10.0", "react-dom": "^18.2.0", - "react-scripts": "^5.0.1" + "react-scripts": "^5.0.1", + "react-scroll": "^1.8.9" }, "devDependencies": { + "eslint-plugin-react-hooks": "^4.6.0", "husky": "^8.0.3", "prettier": "^2.8.4", "pretty-quick": "^3.1.3" @@ -2126,9 +2131,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", + "integrity": "sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -2188,6 +2193,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz", + "integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -3056,6 +3069,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@popperjs/core": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -5143,6 +5165,11 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "node_modules/clean-css": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", @@ -5830,6 +5857,18 @@ "node": ">=10" } }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -6535,11 +6574,12 @@ } }, "node_modules/eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz", + "integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==", "dependencies": { - "@eslint/eslintrc": "^1.4.1", + "@eslint/eslintrc": "^2.0.0", + "@eslint/js": "8.35.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -6553,7 +6593,7 @@ "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", "espree": "^9.4.0", - "esquery": "^1.4.0", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -11409,6 +11449,11 @@ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -11681,6 +11726,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", @@ -13850,6 +13903,23 @@ "node": ">=14" } }, + "node_modules/react-datepicker": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.10.0.tgz", + "integrity": "sha512-6IfBCZyWj54ZZGLmEZJ9c4Yph0s9MVfEGDC2evOvf9AmVz+RRcfP2Czqad88Ff9wREbcbqa4dk7IFYeXF1d3Ag==", + "dependencies": { + "@popperjs/core": "^2.9.2", + "classnames": "^2.2.6", + "date-fns": "^2.24.0", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.12.2", + "react-popper": "^2.3.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18", + "react-dom": "^16.9.0 || ^17 || ^18" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -14041,11 +14111,43 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-onclickoutside": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.12.2.tgz", + "integrity": "sha512-NMXGa223OnsrGVp5dJHkuKxQ4czdLmXSp5jSV9OqiCky9LOpPATn3vLldc+q5fK3gKbEHvr7J1u0yhBh/xYkpA==", + "funding": { + "type": "individual", + "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" + }, + "peerDependencies": { + "react": "^15.5.x || ^16.x || ^17.x || ^18.x", + "react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x" + } + }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -14126,6 +14228,19 @@ } } }, + "node_modules/react-scroll": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/react-scroll/-/react-scroll-1.8.9.tgz", + "integrity": "sha512-9m7ztraiX/l6L7erzYAD3fhnveNckei6/NkWfqwN2e0FRdoE2W6Pk4oi2Nah7mWpPCPAeIgegfaqZACTimPOwg==", + "dependencies": { + "lodash.throttle": "^4.1.1", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "^15.5.4 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.5.4 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -15973,6 +16088,14 @@ "makeerror": "1.0.12" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/package.json b/package.json index e3e1562a7..3c8dcaf95 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,13 @@ "version": "0.1.0", "private": true, "dependencies": { + "eslint": "^8.35.0", + "moment": "^2.29.4", "react": "^18.2.0", + "react-datepicker": "^4.10.0", "react-dom": "^18.2.0", - "react-scripts": "^5.0.1" + "react-scripts": "^5.0.1", + "react-scroll": "^1.8.9" }, "scripts": { "start": "react-scripts start", @@ -14,6 +18,7 @@ "eject": "react-scripts eject" }, "devDependencies": { + "eslint-plugin-react-hooks": "^4.6.0", "husky": "^8.0.3", "prettier": "^2.8.4", "pretty-quick": "^3.1.3" diff --git a/public/index.html b/public/index.html index e4ed67b21..1c38d2406 100644 --- a/public/index.html +++ b/public/index.html @@ -1,19 +1,17 @@ - - - - - - - - - - React App - - - - - - -
- + + + + + + React App + + + + + + + +
+ + - - + + + \ No newline at end of file diff --git a/src/App.css b/src/App.css index 05fe2d52e..3211d0e8a 100644 --- a/src/App.css +++ b/src/App.css @@ -1,57 +1,167 @@ +:root { + --font-paragraph: "Caveat", cursive; + --font-header: "Righteous", cursive; + --dark-blue: #0a2243; + --pink: #9a1076; +} + .App { text-align: left; + font-family: var(--font-paragraph); + position: relative; +} + +.App-title { + font-size: 25px; +} + +/* main-section */ +.main-wrapper { + position: relative; + background-color: rgba(10, 34, 67, 0.5); + padding-bottom: 40px; + min-height: 60vh; +} + +.main-wrapper::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; + background-image: url("./media/main_back_3.jpg"); + background-size: cover; + background-position: center; + background-repeat: no-repeat; } -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 80px; +h1, +h2, +h3, +h4 { + font-family: var(--font-header); } -.App-header { - background-color: #222; - height: 50px; - padding: 20px; +button, +.button { + background-color: var(--pink); color: white; - text-align: left; - font-family: Arial, Helvetica, sans-serif; - font-size: 1em; - font-weight: bold; + border: 1px solid #0a2243; + border-radius: 50px; + padding: 5px 20px; + font-size: 22px; + line-height: 24px; + cursor: pointer; } -.App-title { - font-size: 1.5em; +button:hover, +.button:hover { + background-color: var(--dark-blue); } -.App-content { - padding-top: 20px; - font-size: large; +.main-page-wrapper { + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-auto-rows: 1fr; + grid-template-areas: "form text"; + margin: 20px 40px; } -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } +/* welcome text in main sector */ +.reservation-text { + color: white; + text-align: right; + grid-area: text; } -.search { - padding: 5px 0 20px 0; + +.reservation-text p { + font-size: 25px; + padding: 20px 0 20px 20px; +} + +/* new booking form */ +.new-booking-form { + grid-area: form; + max-width: 80%; + background-color: white; + padding: 20px 30px; + border: 1px solid #0a2243; + border-radius: 20px; + font-size: 22px; } -tr { - color: #5b5757; +.new-booking-form .form-group { + margin: 0; } -.results { - padding-top: 15px; +.new-booking-form .button { + cursor: pointer; + margin-top: 20px; } -.footer { - padding-top: 20px; - text-align: center; +.new-booking-form label { + margin: 0; } -.card { - width: 18rem; +.new-booking-form input { + font-size: 22px; + border: 1px solid #0a2243; + border-radius: 50px; +} + +.footer-list { + background-image: linear-gradient( + 269.87deg, + #0a2243 0.1%, + #203e72 48.95%, + #0a2243 99.87% + ); + list-style: none; + display: flex; + justify-content: space-around; + align-items: center; + font-size: 25px; + padding: 50px 0; + color: white; +} + +.footer-list li { + padding: 10px 0; +} + +.arrow { + position: fixed; + right: 10px; + bottom: 30px; +} + +.arrow:hover { + cursor: pointer; +} + +@media (max-width: 768px) { + .main-page-wrapper { + grid-template-columns: 1fr; + grid-template-rows: repeat(2, auto); + grid-template-areas: + "text" + "form"; + } + + .reservation-text { + text-align: center; + margin-bottom: 30px; + } + + .new-booking-form { + max-width: 100%; + display: block; + margin: 0 auto; + } + + .footer-list { + flex-direction: column; + } } diff --git a/src/App.js b/src/App.js index 953c98560..72421834b 100644 --- a/src/App.js +++ b/src/App.js @@ -1,13 +1,44 @@ -import React from "react"; +import React, { useState } from "react"; import Bookings from "./Bookings"; +import Heading from "./Heading"; +import Footer from "./Footer"; import "./App.css"; +import Restaurant from "./Restaurant"; +import HotelImages from "./HotelImages"; +import NewBookingForm from "./NewBookingForm"; +import WelcomeInfo from "./WelcomeInfo"; +import Attractions from "./Attractions"; +import Arrow from "./Arrow"; const App = () => { + const [guestList, setGuestList] = useState(""); + + let footerArray = [ + "123 Fake Street, London, E1 4UD", + "hello@fakehotel.com", + "0123 456789", + ]; return (
-
CYF Hotel
- +
+ +
+ + +
+
+ + + + + + +
); }; diff --git a/src/Arrow.js b/src/Arrow.js new file mode 100644 index 000000000..1b914fd08 --- /dev/null +++ b/src/Arrow.js @@ -0,0 +1,15 @@ +import React from "react"; +import arrow from "./media/arrow_up.svg"; +import { Link } from "react-scroll"; + +const Arrow = () => { + return ( + + arrow - Go up + + ); + + // arrow - Go up; +}; + +export default Arrow; diff --git a/src/Attractions.css b/src/Attractions.css new file mode 100644 index 000000000..d17da48ce --- /dev/null +++ b/src/Attractions.css @@ -0,0 +1,75 @@ +.attractions { + background-image: linear-gradient( + 269.87deg, + #0a2243 0.1%, + #203e72 48.95%, + #0a2243 99.87% + ); + padding: 5% 40px; +} + +.inside-attractions { + max-width: 1250px; + display: block; + margin: 0 auto; +} + +.attractions h1 { + color: var(--pink); + -webkit-text-stroke: 2px white; + font-size: 100px; + margin-left: 60px; +} + +.info-cards { + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +.card { + width: 22rem; + margin: 0 20px 20px 20px; + border-radius: 0px 50px 50px 0px; + border: 2px solid #9a1076; +} + +.card img { + border-radius: 0px 50px 0px 0px; +} + +.card .card-body { + display: flex; + flex-direction: column; + align-items: center; + font-size: 20px; + min-height: 350px; +} + +.card-body h5 { + font-family: var(--font-header); +} + +@media (max-width: 768px) { + .card { + margin: 20px 20px; + } + + .attractions h1 { + margin-left: 0; + text-align: center; + } +} + +@media (max-width: 620px) { + .attractions h1 { + font-size: 70px; + } +} + +@media (max-width: 450px) { + .attractions h1 { + font-size: 50px; + -webkit-text-stroke: 1px white; + } +} diff --git a/src/Attractions.js b/src/Attractions.js new file mode 100644 index 000000000..c9091ec6a --- /dev/null +++ b/src/Attractions.js @@ -0,0 +1,21 @@ +import React from "react"; +import Cities from "./data/cities.json"; +import TouristInfoCard from "./TouristInfoCard"; +import "./Attractions.css"; + +const Attractions = () => { + return ( +
+
+

Attractions

+
+ {Cities.map((city) => { + return ; + })} +
+
+
+ ); +}; + +export default Attractions; diff --git a/src/Bookings.css b/src/Bookings.css new file mode 100644 index 000000000..f0fb4efca --- /dev/null +++ b/src/Bookings.css @@ -0,0 +1,165 @@ +.container { + width: 100%; + padding: 0; +} + +/* search component */ +.search { + padding: 5px 0 20px 0; + background-image: linear-gradient( + 269.87deg, + #0a2243 0.1%, + #203e72 48.95%, + #0a2243 99.87% + ); + color: white; + padding: 40px; + font-size: 25px; +} + +.search-header { + display: flex; +} + +.search-header h3 { + margin-left: 30px; + font-size: 34px; + font-family: var(--font-paragraph); +} + +.search .col { + padding: 0; +} + +.search-row { + display: flex; + align-items: center; +} + +.search label { + color: white; +} + +.search-row input { + width: 78%; + background-color: transparent; + border: 2px solid #ffffff; + border-radius: 50px; + color: white; + font-size: 22px; +} + +.search-row input::placeholder { + color: rgba(255, 255, 255, 0.641); +} + +.search-buttons { + display: flex; +} + +.search-buttons button { + margin-right: 10px; +} + +/* table */ +.table-wrapper { + position: relative; + background-color: rgba(10, 34, 67, 0.5); + padding-bottom: 40px; + min-height: 50vh; + padding: 40px; + display: flex; + flex-direction: column; + align-items: center; +} + +.table-wrapper::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; + background-image: url(./media/palms.jpg); + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} + +.table { + width: 100%; + background-color: white; + font-size: 25px; +} + +.pink-row th { + background-color: var(--pink) !important; +} + +.pink-row th span { + margin-left: 4px; +} + +tr { + color: #5b5757; + cursor: pointer; + font-size: 26px; +} + +.selected-row { + background-color: var(--dark-blue); + color: white; +} + +/* customer profile */ +.customer-profile { + background-color: white; + border-radius: 0px 50px 50px 0px; + border: 1px solid white; + font-size: 25px; +} + +.customer-profile h3 { + padding: 20px; + background-color: var(--pink); + border-radius: 0px 50px 0 0px; + color: white; +} + +.customer-profile p { + padding: 0 20px; +} + +.results { + padding-top: 15px; +} + +@media (min-width: 768px) { + .container { + max-width: 100%; + } +} + +@media (min-width: 576px) { + .container { + max-width: 100%; + } +} + +@media (max-width: 768px) { + .search-row { + flex-direction: column; + } + + .search-buttons { + margin-top: 20px; + } + + .search-row input { + width: 90%; + } +} + +@media (max-width: 1200px) { +} diff --git a/src/Bookings.js b/src/Bookings.js index e0d911b13..6ae63939b 100644 --- a/src/Bookings.js +++ b/src/Bookings.js @@ -1,18 +1,71 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import Search from "./Search.js"; -// import SearchResults from "./SearchResults.js"; -// import FakeBookings from "./data/fakeBookings.json"; +import SearchResults from "./SearchResults.js"; +import "./Bookings.css"; -const Bookings = () => { - const search = searchVal => { - console.info("TO DO!", searchVal); +const Bookings = ({ bookings, setBookings }) => { + const [fullList, setFullList] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(""); + + //function to show full list of guests + const showFullList = () => { + setBookings(fullList); + }; + + //function to search for guest by name or surname + const search = (searchVal) => { + if (searchVal === "") { + return; + } + const newGuestLists = bookings.filter((guest) => { + if ( + guest.firstName.toLowerCase().includes(searchVal.toLowerCase()) || + guest.surname.toLowerCase().includes(searchVal.toLowerCase()) + ) { + return guest; + } + }); + setBookings(newGuestLists); }; + //getting data about guest from API + useEffect(() => { + setIsLoading(true); + const fetchData = async () => { + try { + let response = await fetch("https://temporary-cyf-react.onrender.com/"); + + if (response.status >= 400 && response.status < 600) { + throw new Error("Bad response from server"); + } else { + let data = await response.json(); + setBookings(data); + setFullList(data); + setIsLoading(false); + } + } catch (error) { + setError(error); + setIsLoading(false); + } + }; + fetchData(); + }, []); + return ( -
+
- - {/* */} + + + {isLoading ?

Please wait for loading data...

: null} + {error !== "" ? ( +

{`We cannot load the page because an error has occurred. ${error}. Please fix the error and try one more time.`}

+ ) : null}
); diff --git a/src/BookingsRow.js b/src/BookingsRow.js new file mode 100644 index 000000000..d38fc668a --- /dev/null +++ b/src/BookingsRow.js @@ -0,0 +1,59 @@ +import React, { useState, useCallback, useEffect } from "react"; +import moment from "moment/moment"; + +const BookingsRow = ({ guest, changeGuestProfile }) => { + const [isSelected, setIsSelected] = useState(false); + const [finalData, setFinalData] = useState(null); + + //getting profile info about guest from API + useEffect(() => { + const fetchGuest = async () => { + const response = await fetch( + `https://temporary-cyf-react.onrender.com/customers/${guest.id}` + ); + const data = await response.json(); + setFinalData(data); + }; + fetchGuest(); + }, [guest.id]); + + //function for highlighting row on a click + const handleTableRowClick = () => setIsSelected(!isSelected); + + //function for button Show Profile + const showProfile = useCallback(() => { + changeGuestProfile(finalData); + }, [changeGuestProfile, finalData]); + + //function for button Hide Profile + const hideProfile = () => { + changeGuestProfile(null); + }; + + return ( + + {guest.id} + {guest.title} + {guest.firstName} + {guest.surname} + {guest.email} + {guest.roomId} + {guest.checkInDate} + {guest.checkOutDate} + {guest.duration} + + {finalData && finalData.hasOwnProperty("id") && ( + <> + + + + )} + + + ); +}; + +export default BookingsRow; diff --git a/src/CustomerProfile.js b/src/CustomerProfile.js new file mode 100644 index 000000000..b77f2abfc --- /dev/null +++ b/src/CustomerProfile.js @@ -0,0 +1,17 @@ +import React from "react"; + +const CustomerProfile = (props) => { + return ( + props.guest !== null && ( +
+

Customer profile

+

Customer id: {props.guest.id}

+

Customer email: {props.guest.email}

+

Customer status: {props.guest.vip === true ? "VIP" : "Normal"}

+

Customer phone number: {props.guest.phoneNumber}

+
+ ) + ); +}; + +export default CustomerProfile; diff --git a/src/Footer.js b/src/Footer.js new file mode 100644 index 000000000..653e7f863 --- /dev/null +++ b/src/Footer.js @@ -0,0 +1,13 @@ +import React from "react"; + +const Footer = (props) => { + return ( + + ); +}; + +export default Footer; diff --git a/src/Heading.css b/src/Heading.css new file mode 100644 index 000000000..f4103305d --- /dev/null +++ b/src/Heading.css @@ -0,0 +1,27 @@ +.navbar { + width: 100%; + padding: 15px 20px; +} + +.navbar-brand { + color: white !important; + font-size: 28px; + font-family: var(--font-header); +} + +.nav-item { + color: white !important; + font-size: 25px; + padding: 0 20px !important; +} + +.nav-item:hover { + color: var(--pink) !important; + cursor: pointer; +} + +.logo { + padding-left: 20px; + height: 70px; + width: auto; +} diff --git a/src/Heading.js b/src/Heading.js new file mode 100644 index 000000000..4347005e7 --- /dev/null +++ b/src/Heading.js @@ -0,0 +1,74 @@ +import React from "react"; +import "./Heading.css"; +import logo from "./media/logo.png"; +import { Link } from "react-scroll"; + +const Heading = () => { + return ( +
+ +
+ ); +}; + +export default Heading; diff --git a/src/HotelImages.css b/src/HotelImages.css new file mode 100644 index 000000000..5715809a9 --- /dev/null +++ b/src/HotelImages.css @@ -0,0 +1,57 @@ +.image-slider { + width: 100%; + height: auto; + display: block; + margin: 0 auto; +} + +.box::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(10, 34, 67, 0.3); +} + +.image-slider .frame { + width: 100%; + height: 550px; +} + +.image-slider .boxes { + display: flex; + width: 100%; + height: 100%; +} + +.image-slider .box { + position: relative; + flex: 1 1 auto; + width: 20%; + background: grey; + transition: all 0.8s ease-in-out; + cursor: pointer; + overflow: hidden; + background-repeat: no-repeat; + background-size: cover; + background-position: center; +} + +.image-slider .box:hover { + width: 100%; +} + +.image-slider .box-1 { + background-image: url("./media/HotelImage_1.jpg"); +} +.image-slider .box-2 { + background-image: url("./media/HotelImage_2.jpg"); +} +.image-slider .box-3 { + background-image: url("./media/HotelImage_3.webp"); +} +.image-slider .box-4 { + background-image: url("./media/HotelImage_4.webp"); +} diff --git a/src/HotelImages.js b/src/HotelImages.js new file mode 100644 index 000000000..4a08d67f4 --- /dev/null +++ b/src/HotelImages.js @@ -0,0 +1,21 @@ +import React from "react"; +import "./HotelImages.css"; + +const HotelImages = () => { + return ( +
+
+
+
+
+
+
+
+
+
+
+
+ ); +}; + +export default HotelImages; diff --git a/src/NewBookingForm.js b/src/NewBookingForm.js new file mode 100644 index 000000000..88f8a6129 --- /dev/null +++ b/src/NewBookingForm.js @@ -0,0 +1,262 @@ +import React, { useState } from "react"; +import DatePicker from "react-datepicker"; + +import "react-datepicker/dist/react-datepicker.css"; + +const NewBookingForm = ({ bookingsList, addNewBooking }) => { + const [formInputs, setFormInputs] = useState({ + title: "", + firstName: "", + surname: "", + email: "", + }); + const [validationErrors, setValidationErrors] = useState({ + title: "", + firstName: "", + surname: "", + email: "", + }); + + //creating stated for min max value in calendar + const [startDate, setStartDate] = useState(new Date()); + const [endDate, setEndDate] = useState(addTenDaysToDate(new Date())); + //message will show up after submit button is clicked + const [message, setMessage] = useState(""); + //created this state to force Restaurant component to re-render + const [key, setKey] = useState(0); + + //on every change of user inside any input field + const handleChange = (event) => { + //inside state we have name of input and value + const { name, value } = event.target; + //object for collecting errors + let errors = { ...validationErrors }; + + switch (name) { + case "title": + errors.title = !value.trim() + ? "X Title is required" + : value.length < 2 + ? "X Title must be at least 2 characters" + : ""; + break; + case "firstName": + errors.firstName = !value.trim() + ? "X First name is required" + : value.length < 3 + ? "X First name must be at least 3 characters" + : ""; + break; + case "surname": + errors.surname = !value.trim() + ? "X Surname is required" + : value.length < 3 + ? "X Surname must be at least 3 characters" + : ""; + break; + case "email": + errors.email = !/^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/.test(value) + ? "X Email is invalid" + : value.length < 6 + ? "X Email must be at least 6 characters" + : ""; + break; + default: + break; + } + + setValidationErrors(errors); + setFormInputs({ ...formInputs, [name]: value }); + }; + + //handling submission of a form + const handleSubmit = (event) => { + event.preventDefault(); + + //creating a new object + let obj = {}; + obj.id = generateRandomID(); + obj.title = formInputs.title; + obj.firstName = formInputs.firstName; + obj.surname = formInputs.surname; + obj.email = formInputs.email; + obj.roomId = generateRandomRoomID(); + obj.checkInDate = formatDate(startDate); + obj.checkOutDate = formatDate(endDate); + + //adding new guest to the main list + addNewBooking([...bookingsList, obj]); + + //clearing all input fields in form + setFormInputs({ + title: "", + firstName: "", + surname: "", + email: "", + }); + }; + + //creating random number for id + const generateRandomID = () => { + let randId = Math.trunc(Math.random() * 50) + 1; + + // check if generated ID exists in bookingsList + while (bookingsList.some((guest) => guest.id === randId)) { + randId = Math.trunc(Math.random() * 50) + 1; + } + + //show message after button was clicked for 6 seconds + setMessage( + "Your reservation has been accepted. You can check it in guest list." + ); + setTimeout(() => { + setMessage(""); + }, 6000); + setKey(key + 1); + + return randId; + }; + + //creating random number for room id + const generateRandomRoomID = () => { + let randId = Math.trunc(Math.random() * 50) + 1; + + // check if generated ID exists in bookingsList + while (bookingsList.some((guest) => guest.roomId === randId)) { + randId = Math.trunc(Math.random() * 50) + 1; + } + + return randId; + }; + + //function for formatting date + function formatDate(date) { + console.log(date); + console.log(typeof date); + + let now = date; + let year = now.getFullYear(); + let month = now.getMonth() + 1; + let day = now.getDate(); + //adding 0 to day and month if the number is less than 10 + let newDay = ("0" + day).slice(-2); + let newMonth = ("0" + month).slice(-2); + let myDate = `${year}-${newMonth}-${newDay}`; + + return myDate; + } + + //function which add ten days to any passed date + function addTenDaysToDate(date) { + const newDate = new Date(date.getTime()); + newDate.setDate(newDate.getDate() + 10); + return newDate; + } + + return ( +
+
+
+ + +

{validationErrors.firstName}

+
+
+ + +

{validationErrors.surname}

+
+
+ +
+
+ + +

{validationErrors.email}

+
+
+ + +

{validationErrors.title}

+
+
+ +
+
+ + setStartDate(date)} + selectsStart + startDate={startDate} + endDate={endDate} + minDate={new Date()} + required + /> +
+
+ + setEndDate(date)} + selectsEnd + startDate={startDate} + endDate={endDate} + minDate={startDate} + required + /> +
+
+ + + {message &&

{message}

} +
+ ); +}; + +export default NewBookingForm; diff --git a/src/Order.js b/src/Order.js new file mode 100644 index 000000000..83eea4c2e --- /dev/null +++ b/src/Order.js @@ -0,0 +1,16 @@ +import React, { useState } from "react"; +import RestaurantButton from "./RestaurantButton"; + +const Order = (props) => { + const [orders, setOrders] = useState(0); + const orderOne = () => { + setOrders(orders + 1); + }; + return ( +
  • + {props.orderType}: {orders} +
  • + ); +}; + +export default Order; diff --git a/src/Restaurant.css b/src/Restaurant.css new file mode 100644 index 000000000..16deb58fb --- /dev/null +++ b/src/Restaurant.css @@ -0,0 +1,123 @@ +.restaurant { + display: grid; + grid-template-columns: 1.5fr 1fr; + grid-auto-rows: 1fr; + grid-template-areas: "image text"; + min-height: 60vh; + position: relative; +} + +.image-back { + position: relative; + background-color: rgba(10, 34, 67, 0.5); + padding-bottom: 40px; + grid-area: image; +} + +.image-back::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; + background-image: url(./media/food_2.jpg); + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} + +.text-section { + grid-area: text; + align-self: center; +} + +.text-section h1 { + position: absolute; + top: 10%; + right: 40px; + color: var(--dark-blue); + -webkit-text-stroke: 2px white; + font-size: 110px; + margin-left: 60px; + width: 100%; + text-align: right; + font-size: 85px; + line-height: 80px; +} + +.food-list { + margin-top: 120px; +} + +.food-list li { + display: flex; + justify-content: space-between; + font-size: 30px; + padding: 20px 0; +} + +.food-list .add-order-button { + margin-right: 40px; +} + +.send-order-button { + width: 80%; + + display: block; + margin: 20px auto; + font-size: 26px; +} + +.order-message { + font-size: 25px; + text-align: center; + margin: 10px 40px; +} + +@media (max-width: 880px) { + .restaurant { + grid-template-columns: 1fr; + grid-template-rows: 1fr 1fr; + grid-template-areas: + "image" + "text"; + } + + .food-list { + margin-top: 0; + } + + .send-order-button { + width: 350px; + width: 90%; + } +} + +@media (max-width: 590px) { + .text-section h1 { + font-size: 80px; + line-height: 70px; + } +} + +@media (max-width: 476px) { + .text-section h1 { + font-size: 65px; + line-height: 70px; + } +} + +@media (max-width: 390px) { + .text-section h1 { + font-size: 50px; + line-height: 60px; + } +} + +@media (max-height: 1030px) { + .text-section h1 { + top: 0; + } +} diff --git a/src/Restaurant.js b/src/Restaurant.js index ecb2b43a2..d05bf9ad1 100644 --- a/src/Restaurant.js +++ b/src/Restaurant.js @@ -1,15 +1,39 @@ -import React from "react"; +import React, { useState } from "react"; +import Order from "./Order"; +import "./Restaurant.css"; const Restaurant = () => { - const pizzas = 0; + const food = ["BLT Sandwich", "Caesar Salad", "Tuna Melt"]; + const [message, setMessage] = useState(""); + //created this state to force Restaurant component to re-render + const [key, setKey] = useState(0); + + //handling click of Send order button, show message for 6 seconds + const handleClick = () => { + setMessage( + "Your order has been sent! Please wait 10 minutes for your order. Enjoy!" + ); + setTimeout(() => { + setMessage(""); + }, 6000); + setKey(key + 1); + }; + return ( -
    -

    Restaurant Orders

    - +
    +
    +
    +

    Order some food

    +
      + {food.map((x, index) => { + return ; + })} +
    + + {message &&

    {message}

    } +
    ); }; diff --git a/src/RestaurantButton.js b/src/RestaurantButton.js new file mode 100644 index 000000000..d3aa84548 --- /dev/null +++ b/src/RestaurantButton.js @@ -0,0 +1,14 @@ +import React from "react"; + +const RestaurantButton = (props) => { + return ( + + ); +}; + +export default RestaurantButton; diff --git a/src/Search.js b/src/Search.js index 7bd5871c0..56f6c8052 100644 --- a/src/Search.js +++ b/src/Search.js @@ -1,23 +1,51 @@ -import React from "react"; +import React, { useState } from "react"; +import SearchButton from "./SearchButton"; +import ShowFullListButton from "./ShowFullListButton"; + +const Search = (props) => { + const [searchInput, setSearchInput] = useState(""); + + //on change saving the value from input field + const handleSearchInput = (event) => { + setSearchInput(event.target.value); + }; + + //on submit displaying guest + const handleSubmit = (event) => { + event.preventDefault(); + props.search(searchInput); + //removing value from the input field + if (searchInput !== "") { + setSearchInput(""); + props.search(""); + } + }; -const Search = () => { return (
    -

    Search Bookings

    +
    +

    Guest list

    +

    - Search bookings

    {" "} +
    -
    +
    - +
    + + +
    diff --git a/src/SearchButton.js b/src/SearchButton.js new file mode 100644 index 000000000..6c73b524c --- /dev/null +++ b/src/SearchButton.js @@ -0,0 +1,7 @@ +import React from "react"; + +const SearchButton = () => { + return ; +}; + +export default SearchButton; diff --git a/src/SearchResults.js b/src/SearchResults.js new file mode 100644 index 000000000..6be40a51d --- /dev/null +++ b/src/SearchResults.js @@ -0,0 +1,145 @@ +import React, { useState, useEffect, useCallback } from "react"; +import BookingsRow from "./BookingsRow"; +import CustomerProfile from "./CustomerProfile"; +import moment from "moment/moment"; + +const SearchResults = (props) => { + const [guestProfile, setGuestProfile] = useState(null); + + //these two states are created for sorting columns in table + const [data, setData] = useState(props.results); + const [sortStates, setSortStates] = useState(Array(9).fill(false)); + + //to keep track of the last sorted column and the last sort order + const [lastSortedColumn, setLastSortedColumn] = useState(""); + const [lastSortOrder, setLastSortOrder] = useState(""); + + //to update the state of data whenever props.results changes. + useEffect(() => { + setData(props.results); + setSortStates(Array(9).fill(false)); + }, [props.results, setData, setSortStates]); + + //sorting columns in the table + const sortBy = (property, index) => { + let newSortOrder; + if (property === lastSortedColumn) { + newSortOrder = lastSortOrder === "asc" ? "desc" : "asc"; + setSortStates((prevStates) => + prevStates.map((state, i) => (i === index ? !state : state)) + ); + } else { + newSortOrder = "asc"; + setSortStates(Array(9).fill(false)); + setSortStates((prevStates) => + prevStates.map((state, i) => (i === index ? !state : state)) + ); + } + setLastSortedColumn(property); + setLastSortOrder(newSortOrder); + setData((prevData) => { + const sortedData = [...prevData].sort((a, b) => { + if (typeof a[property] === "number") { + if (newSortOrder === "asc") { + return a[property] - b[property]; + } else { + return b[property] - a[property]; + } + } else { + if (newSortOrder === "asc") { + return a[property] < b[property] ? -1 : 1; + } else { + return a[property] < b[property] ? 1 : -1; + } + } + }); + + return sortedData; + }); + }; + + //calculating number of nights + const calculateNights = useCallback((firstDate, secondDate) => { + let first = moment(firstDate, "YYYY-MM-DD"); + let second = moment(secondDate, "YYYY-MM-DD"); + return second.diff(first, "days"); + }, []); + + //function for adding duration key and value to the array of guests + const addDurationToGuest = (array) => { + if (array.length > 0) { + array.forEach((guest) => { + guest.duration = calculateNights(guest.checkInDate, guest.checkOutDate); + }); + } + return array; + }; + + //to add duration field to the array, so then we can sort number of nights column in table + useEffect(() => { + setData(addDurationToGuest(data)); + }, [data]); + + return ( +
    + + + + + + + + + + + + + + + + + {data.length > 0 && + data.map((guest) => ( + + ))} + +
    sortBy("id", 0)}> + Id + + {sortStates[0] ? "↑" : "↓"} + + sortBy("title", 1)}> + Title + {sortStates[1] ? "↑" : "↓"} + sortBy("firstName", 2)}> + First name + {sortStates[2] ? "↑" : "↓"} + sortBy("surname", 3)}> + Surname + {sortStates[3] ? "↑" : "↓"} + sortBy("email", 4)}> + EMAIL + {sortStates[4] ? "↑" : "↓"} + sortBy("roomId", 5)}> + Room id + {sortStates[5] ? "↑" : "↓"} + sortBy("checkInDate", 6)}> + Check in date + {sortStates[6] ? "↑" : "↓"} + sortBy("checkOutDate", 7)}> + Check out date + {sortStates[7] ? "↑" : "↓"} + sortBy("duration", 8)}> + Number of nights + {sortStates[8] ? "↑" : "↓"} + Profile
    + +
    + ); +}; + +export default SearchResults; diff --git a/src/ShowFullListButton.js b/src/ShowFullListButton.js new file mode 100644 index 000000000..b980b6ea0 --- /dev/null +++ b/src/ShowFullListButton.js @@ -0,0 +1,11 @@ +import React from "react"; + +const ShowFullListButton = (props) => { + const displayFullList = () => { + props.showFullList(); + }; + + return ; +}; + +export default ShowFullListButton; diff --git a/src/TouristInfoCard.js b/src/TouristInfoCard.js new file mode 100644 index 000000000..91649845b --- /dev/null +++ b/src/TouristInfoCard.js @@ -0,0 +1,22 @@ +import React from "react"; + +const TouristInfoCard = (props) => { + return ( +
    + +
    +
    {props.city.name}
    +

    {props.city.description}

    + + More information + +
    +
    + ); +}; + +export default TouristInfoCard; diff --git a/src/WelcomeInfo.js b/src/WelcomeInfo.js new file mode 100644 index 000000000..8096e246b --- /dev/null +++ b/src/WelcomeInfo.js @@ -0,0 +1,27 @@ +import React from "react"; +import { Link } from "react-scroll"; + +const WelcomeInfo = () => { + return ( +
    +

    Make Reservation

    +

    + Welcome to our collection of exceptional hotels! Whether you're + traveling for business or pleasure, we have the perfect accommodations + to suit your needs and exceed your expectations. +

    + + Check all guests + +
    + ); +}; + +export default WelcomeInfo; diff --git a/src/data/cities.json b/src/data/cities.json new file mode 100644 index 000000000..e42061ecd --- /dev/null +++ b/src/data/cities.json @@ -0,0 +1,23 @@ +[ + { + "id": 1, + "name": "London", + "description": "It is the largest metropolis in the United Kingdom, and it is also the country's economic, transportation, and cultural centre. It is the largest metropolis in the United Kingdom, and it is also the country's economic, transportation, and cultural centre. ", + "image": "https://i.natgeofe.com/n/93231b5d-3b4f-4bd6-bcf4-4172ebda2011/parliment-square-london-england_3x2.jpg", + "link": "https://www.visitlondon.com/" + }, + { + "id": 2, + "name": "Glasgow", + "description": "Glasgow is a port city on the River Clyde in Scotland's western Lowlands. ", + "image": "https://www.greatbritishbucketlist.com/wp-content/uploads/2021/04/glasgow-4-1024x682.jpg", + "link": "http://peoplemakeglasgow.com/" + }, + { + "id": 3, + "name": "Manchester", + "description": "Manchester is a major city in the northwest of England with a rich industrial heritage.", + "image": "https://eu-assets.simpleview-europe.com/manchester2016/imageresizer/?image=%2Fdbimgs%2Folympic-parade%20%281%29-min.jpg&action=BlogDetailContent", + "link": "https://www.visitmanchester.com/" + } +] diff --git a/src/media/Big_hotel.jpg b/src/media/Big_hotel.jpg new file mode 100644 index 000000000..cb80f4cb5 Binary files /dev/null and b/src/media/Big_hotel.jpg differ diff --git a/src/media/HotelImage_1.jpg b/src/media/HotelImage_1.jpg new file mode 100644 index 000000000..e96e34b7e Binary files /dev/null and b/src/media/HotelImage_1.jpg differ diff --git a/src/media/HotelImage_2.jpg b/src/media/HotelImage_2.jpg new file mode 100644 index 000000000..1d59efbb4 Binary files /dev/null and b/src/media/HotelImage_2.jpg differ diff --git a/src/media/HotelImage_3.webp b/src/media/HotelImage_3.webp new file mode 100644 index 000000000..98d7dcb4e Binary files /dev/null and b/src/media/HotelImage_3.webp differ diff --git a/src/media/HotelImage_4.webp b/src/media/HotelImage_4.webp new file mode 100644 index 000000000..1ad51c4e3 Binary files /dev/null and b/src/media/HotelImage_4.webp differ diff --git a/src/media/arrow_up.svg b/src/media/arrow_up.svg new file mode 100644 index 000000000..9374a6fd3 --- /dev/null +++ b/src/media/arrow_up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/media/bedandsee.webp b/src/media/bedandsee.webp new file mode 100644 index 000000000..cc2d8e357 Binary files /dev/null and b/src/media/bedandsee.webp differ diff --git a/src/media/food.jpg b/src/media/food.jpg new file mode 100644 index 000000000..e1b2f81b9 Binary files /dev/null and b/src/media/food.jpg differ diff --git a/src/media/food_2.jpg b/src/media/food_2.jpg new file mode 100644 index 000000000..0d45c44c7 Binary files /dev/null and b/src/media/food_2.jpg differ diff --git a/src/media/ham-menu.png b/src/media/ham-menu.png new file mode 100644 index 000000000..c624cab89 Binary files /dev/null and b/src/media/ham-menu.png differ diff --git a/src/media/logo.png b/src/media/logo.png new file mode 100644 index 000000000..b4bd9e9b9 Binary files /dev/null and b/src/media/logo.png differ diff --git a/src/media/logo2.png b/src/media/logo2.png new file mode 100644 index 000000000..8919f58c7 Binary files /dev/null and b/src/media/logo2.png differ diff --git a/src/media/main_back_2.jpg b/src/media/main_back_2.jpg new file mode 100644 index 000000000..d9f83ee9b Binary files /dev/null and b/src/media/main_back_2.jpg differ diff --git a/src/media/main_back_3.jpg b/src/media/main_back_3.jpg new file mode 100644 index 000000000..21f56944e Binary files /dev/null and b/src/media/main_back_3.jpg differ diff --git a/src/media/palms.jpg b/src/media/palms.jpg new file mode 100644 index 000000000..fbe3fe595 Binary files /dev/null and b/src/media/palms.jpg differ