пятое сохранение
This commit is contained in:
87
keynest/package-lock.json
generated
87
keynest/package-lock.json
generated
@@ -12,9 +12,11 @@
|
|||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/react": "^16.2.0",
|
"@testing-library/react": "^16.2.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
"lorem-ipsum": "^2.0.8",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-router-dom": "^7.4.1",
|
"react-modal": "^3.16.3",
|
||||||
|
"react-router-dom": "^7.5.1",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"styled-components": "^6.1.16",
|
"styled-components": "^6.1.16",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
@@ -3674,12 +3676,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/cookie": {
|
|
||||||
"version": "0.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
|
||||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@types/eslint": {
|
"node_modules/@types/eslint": {
|
||||||
"version": "8.56.12",
|
"version": "8.56.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.12.tgz",
|
||||||
@@ -7902,6 +7898,12 @@
|
|||||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/exenv": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/exit": {
|
"node_modules/exit": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
||||||
@@ -11272,6 +11274,31 @@
|
|||||||
"loose-envify": "cli.js"
|
"loose-envify": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lorem-ipsum": {
|
||||||
|
"version": "2.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/lorem-ipsum/-/lorem-ipsum-2.0.8.tgz",
|
||||||
|
"integrity": "sha512-5RIwHuCb979RASgCJH0VKERn9cQo/+NcAi2BMe9ddj+gp7hujl6BI+qdOG4nVsLDpwWEJwTVYXNKP6BGgbcoGA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^9.3.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"lorem-ipsum": "dist/bin/lorem-ipsum.bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.x",
|
||||||
|
"npm": ">= 5.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lorem-ipsum/node_modules/commander": {
|
||||||
|
"version": "9.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||||
|
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lower-case": {
|
"node_modules/lower-case": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||||
@@ -13987,6 +14014,28 @@
|
|||||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/react-lifecycles-compat": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/react-modal": {
|
||||||
|
"version": "3.16.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.3.tgz",
|
||||||
|
"integrity": "sha512-yCYRJB5YkeQDQlTt17WGAgFJ7jr2QYcWa1SHqZ3PluDmnKJ/7+tVU+E6uKyZ0nODaeEj+xCpK4LcSnKXLMC0Nw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"exenv": "^1.2.0",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react-lifecycles-compat": "^3.0.0",
|
||||||
|
"warning": "^4.0.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19",
|
||||||
|
"react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
||||||
@@ -13997,12 +14046,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "7.4.1",
|
"version": "7.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.1.tgz",
|
||||||
"integrity": "sha512-Vmizn9ZNzxfh3cumddqv3kLOKvc7AskUT0dC1prTabhiEi0U4A33LmkDOJ79tXaeSqCqMBXBU/ySX88W85+EUg==",
|
"integrity": "sha512-/jjU3fcYNd2bwz9Q0xt5TwyiyoO8XjSEFXJY4O/lMAlkGTHWuHRAbR9Etik+lSDqMC7A7mz3UlXzgYT6Vl58sA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cookie": "^0.6.0",
|
|
||||||
"cookie": "^1.0.1",
|
"cookie": "^1.0.1",
|
||||||
"set-cookie-parser": "^2.6.0",
|
"set-cookie-parser": "^2.6.0",
|
||||||
"turbo-stream": "2.4.0"
|
"turbo-stream": "2.4.0"
|
||||||
@@ -14021,12 +14069,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router-dom": {
|
"node_modules/react-router-dom": {
|
||||||
"version": "7.4.1",
|
"version": "7.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.1.tgz",
|
||||||
"integrity": "sha512-L3/4tig0Lvs6m6THK0HRV4eHUdpx0dlJasgCxXKnavwhh4tKYgpuZk75HRYNoRKDyDWi9QgzGXsQ1oQSBlWpAA==",
|
"integrity": "sha512-5DPSPc7ENrt2tlKPq0FtpG80ZbqA9aIKEyqX6hSNJDlol/tr6iqCK4crqdsusmOSSotq6zDsn0y3urX9TuTNmA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-router": "7.4.1"
|
"react-router": "7.5.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
@@ -16837,6 +16885,15 @@
|
|||||||
"makeerror": "1.0.12"
|
"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==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/watchpack": {
|
"node_modules/watchpack": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/react": "^16.2.0",
|
"@testing-library/react": "^16.2.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
"lorem-ipsum": "^2.0.8",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-router-dom": "^7.4.1",
|
"react-modal": "^3.16.3",
|
||||||
|
"react-router-dom": "^7.5.1",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"styled-components": "^6.1.16",
|
"styled-components": "^6.1.16",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
|
|||||||
@@ -1,25 +1,50 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import ApartmentRentals from './components/ApartmentRentals';
|
import ApartmentRentals from './components/ApartmentRentals';
|
||||||
import ApartmentOptions from './components/ApartmentOptions';
|
import ApartmentOptions from './components/ApartmentOptions';
|
||||||
import ApartmentAmenities from './components/ApartmentAmenities';
|
import { AuthProvider, useAuth } from './components/AuthContext';
|
||||||
import NearbyAttractions from './components/NearbyAttractions';
|
import BookingPage from './components/BookingPage';
|
||||||
import FlexibleLeasing from './components/FlexibleLeasing';
|
import MyRentals from './components/MyRentals';
|
||||||
import UnparalleledConvenience from './components/UnparalleledConvenience';
|
import Footer from './components/Footer';
|
||||||
|
|
||||||
|
function AppContent() {
|
||||||
|
const { isLoggedIn, logout, user } = useAuth();
|
||||||
|
|
||||||
function App() {
|
|
||||||
return (
|
return (
|
||||||
<div className='app'>
|
<div className='app'>
|
||||||
<Header />
|
<Header />
|
||||||
|
{isLoggedIn ? (
|
||||||
|
<>
|
||||||
<ApartmentRentals />
|
<ApartmentRentals />
|
||||||
<ApartmentOptions />
|
<ApartmentOptions />
|
||||||
<ApartmentAmenities />
|
<Footer />
|
||||||
<NearbyAttractions />
|
</>
|
||||||
<FlexibleLeasing />
|
) : (
|
||||||
<UnparalleledConvenience />
|
<>
|
||||||
|
<ApartmentRentals />
|
||||||
|
<ApartmentOptions />
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<Router>
|
||||||
|
<AuthProvider>
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<AppContent />} />
|
||||||
|
<Route path="/" element={<ApartmentRentals />} />
|
||||||
|
<Route path="/booking" element={<BookingPage />} />
|
||||||
|
<Route path="/myrentals" element={<MyRentals />} />
|
||||||
|
</Routes>
|
||||||
|
</AuthProvider>
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
.apartment_header{
|
|
||||||
background-color: #FCFBFC;
|
|
||||||
}
|
|
||||||
.apartment__Amenities{
|
|
||||||
position: absolute;
|
|
||||||
width: 1290px;
|
|
||||||
height: 187px;
|
|
||||||
top: 800px;
|
|
||||||
text-align: center;
|
|
||||||
left: 290px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
.icon__Amenities{
|
|
||||||
position: absolute;
|
|
||||||
width: 43px;
|
|
||||||
height: 44px;
|
|
||||||
left: 624px;
|
|
||||||
}
|
|
||||||
.heading__Amenities{
|
|
||||||
position: absolute;
|
|
||||||
width: 1290px;
|
|
||||||
height: 56px;
|
|
||||||
top: 61px;
|
|
||||||
font-family: 'Instrument Serif';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 46px;
|
|
||||||
line-height: 120%;
|
|
||||||
text-align: center;
|
|
||||||
color: #1F1E1F;
|
|
||||||
}
|
|
||||||
.info__Amenities{
|
|
||||||
position: absolute;
|
|
||||||
width: 608px;
|
|
||||||
height: 54px;
|
|
||||||
left: 341px;
|
|
||||||
top: 131px;
|
|
||||||
font-family: 'Nunito';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 150%;
|
|
||||||
text-align: center;
|
|
||||||
color: #999798;
|
|
||||||
}
|
|
||||||
.img__Amenitiess{
|
|
||||||
position: absolute;
|
|
||||||
width: 1281px;
|
|
||||||
height: 587px;
|
|
||||||
left: 379px;
|
|
||||||
top: 1000px;
|
|
||||||
display: flex;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.img__Amenities{
|
|
||||||
width: 377px;
|
|
||||||
height: 506px;
|
|
||||||
align-self: stretch;
|
|
||||||
padding-right: 25px;
|
|
||||||
}
|
|
||||||
.img__Amenities1{
|
|
||||||
width: 779px;
|
|
||||||
height: 506px;
|
|
||||||
border-radius: 0px;
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
.img_name{
|
|
||||||
font-family: 'Nunito';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 19px;
|
|
||||||
line-height: 120%;
|
|
||||||
color: #666464;
|
|
||||||
flex: none;
|
|
||||||
}
|
|
||||||
.img_info{
|
|
||||||
font-family: 'Nunito';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 17px;
|
|
||||||
line-height: 120%;
|
|
||||||
color: #727174;
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
|
||||||
import './ApartmentAmenities.css';
|
|
||||||
|
|
||||||
function ApartmentAmenities(){
|
|
||||||
return(
|
|
||||||
<header className='apartment'>
|
|
||||||
<div className='apartment_header'>
|
|
||||||
<div className='apartment__Amenities'>
|
|
||||||
<img className ='icon__Amenities' src={process.env.PUBLIC_URL + '/images/Icon.jpg'} alt='изображение' />
|
|
||||||
<h1 className='heading__Amenities'>Apartment Amenities</h1>
|
|
||||||
<p className='info__Amenities'>Enjoy a range of modern amenities in our apartments, from fully-equipped kitchens to en-suite laundry facilities, ensuring your comfort and convenience</p>
|
|
||||||
</div>
|
|
||||||
<div className='img__Amenitiess'>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Amenities' src={process.env.PUBLIC_URL + '/images/Image2.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Stunning Views</p>
|
|
||||||
<p className='img_info'>Natural Lighting</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Amenities1' src={process.env.PUBLIC_URL + '/images/Image3.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Relaxing Atmosphere</p>
|
|
||||||
<p className='img_info'>Cozy Interiors</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ApartmentAmenities;
|
|
||||||
@@ -1,18 +1,41 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import './ApartmentRentals.css';
|
import './ApartmentRentals.css';
|
||||||
|
|
||||||
function ApartmentRentals(){
|
function ApartmentRentals() {
|
||||||
return(
|
const [loading, setLoading] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleBookNowClick = () => {
|
||||||
|
setLoading(true);
|
||||||
|
// Simulate loading delay
|
||||||
|
setTimeout(() => {
|
||||||
|
setLoading(false);
|
||||||
|
// Redirect to the booking page using navigate
|
||||||
|
navigate('/booking');
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
<header className='apartment'>
|
<header className='apartment'>
|
||||||
<img className ='backround__section' src={process.env.PUBLIC_URL + '/images/Section.png'} alt='изображение' />
|
<img
|
||||||
|
className='backround__section'
|
||||||
|
src={process.env.PUBLIC_URL + '/images/Section.png'}
|
||||||
|
alt='изображение'
|
||||||
|
/>
|
||||||
<div className='Apartament__content'>
|
<div className='Apartament__content'>
|
||||||
<h1 className='heading'>Short-term and Long-term Apartment Rentals</h1>
|
<h1 className='heading'>Short-term and Long-term Apartment Rentals</h1>
|
||||||
<p className='info'>Discover the perfect apartment for your needs, whether it's a quick stay or a long-term investment</p>
|
<p className='info'>Discover the perfect apartment for your needs, whether it's a quick stay or a long-term investment</p>
|
||||||
<button className='content__button'>Book Now</button>
|
<button
|
||||||
|
className='content__button'
|
||||||
|
onClick={handleBookNowClick}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
{loading ? 'Booking...' : 'Book Now'}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ApartmentRentals;
|
export default ApartmentRentals;
|
||||||
57
keynest/src/components/AuthContext.js
Normal file
57
keynest/src/components/AuthContext.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import React, { createContext, useState, useContext } from 'react';
|
||||||
|
|
||||||
|
const AuthContext = createContext();
|
||||||
|
|
||||||
|
export const AuthProvider = ({ children }) => { // ONE declaration of AuthProvider
|
||||||
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||||
|
const [user, setUser] = useState(null);
|
||||||
|
|
||||||
|
const login = async (credentials) => {
|
||||||
|
// Mock authentication logic
|
||||||
|
if (credentials.username === 'user' && credentials.password === 'password') {
|
||||||
|
setIsLoggedIn(true);
|
||||||
|
setUser({ username: credentials.username });
|
||||||
|
return Promise.resolve(); // Resolve promise on successful login
|
||||||
|
} else {
|
||||||
|
setIsLoggedIn(false);
|
||||||
|
setUser(null);
|
||||||
|
return Promise.reject(new Error('Invalid credentials')); // Reject promise on invalid credentials
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const register = async (credentials) => {
|
||||||
|
// Mock registration logic
|
||||||
|
if (credentials.username && credentials.password) {
|
||||||
|
setIsLoggedIn(true);
|
||||||
|
setUser({ username: credentials.username });
|
||||||
|
return Promise.resolve(); // Resolve promise on successful registration
|
||||||
|
} else {
|
||||||
|
setIsLoggedIn(false);
|
||||||
|
setUser(null);
|
||||||
|
return Promise.reject(new Error('Registration failed')); // Reject promise on failed registration
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
setIsLoggedIn(false);
|
||||||
|
setUser(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = {
|
||||||
|
isLoggedIn,
|
||||||
|
user,
|
||||||
|
login,
|
||||||
|
register,
|
||||||
|
logout
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</AuthContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAuth = () => {
|
||||||
|
return useContext(AuthContext);
|
||||||
|
};
|
||||||
128
keynest/src/components/AuthModal.js
Normal file
128
keynest/src/components/AuthModal.js
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import Modal from 'react-modal';
|
||||||
|
import { useAuth } from './AuthContext';
|
||||||
|
|
||||||
|
Modal.setAppElement('#root');
|
||||||
|
|
||||||
|
const AuthModal = ({ isOpen, onRequestClose }) => {
|
||||||
|
const [isLogin, setIsLogin] = useState(true);
|
||||||
|
const [username, setUsername] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
const { login, register } = useAuth();
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setError('');
|
||||||
|
try {
|
||||||
|
if (isLogin) {
|
||||||
|
await login({ username, password });
|
||||||
|
} else {
|
||||||
|
await register({ username, password });
|
||||||
|
}
|
||||||
|
onRequestClose();
|
||||||
|
} catch (err) {
|
||||||
|
setError(err.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleAuthMode = () => {
|
||||||
|
setIsLogin(!isLogin);
|
||||||
|
setUsername('');
|
||||||
|
setPassword('');
|
||||||
|
setError('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const modalStyles = {
|
||||||
|
overlay: {
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.5)'
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
right: 'auto',
|
||||||
|
bottom: 'auto',
|
||||||
|
marginRight: '-50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
padding: '20px',
|
||||||
|
width: '300px',
|
||||||
|
borderRadius: '8px',
|
||||||
|
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)',
|
||||||
|
border: 'none'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const formStyles = {
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '15px'
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputStyles = {
|
||||||
|
padding: '10px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
border: '1px solid #ccc',
|
||||||
|
fontSize: '16px'
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttonStyles = {
|
||||||
|
padding: '12px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
border: 'none',
|
||||||
|
backgroundColor: '#242323',
|
||||||
|
color: 'white',
|
||||||
|
fontSize: '16px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
':hover': {
|
||||||
|
backgroundColor: '#0056b3'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleButtonStyles = {
|
||||||
|
background: 'none',
|
||||||
|
border: 'none',
|
||||||
|
color: '#007bff',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontSize: '14px',
|
||||||
|
textDecoration: 'underline'
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
onRequestClose={onRequestClose}
|
||||||
|
style={modalStyles}
|
||||||
|
>
|
||||||
|
<h2 style={{ textAlign: 'center', marginBottom: '20px' }}>{isLogin ? 'Login' : 'Register'}</h2>
|
||||||
|
{error && <p style={{ color: 'red', textAlign: 'center' }}>{error}</p>}
|
||||||
|
<form onSubmit={handleSubmit} style={formStyles}>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="username" style={{ marginBottom: '5px', display: 'block' }}>Username:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="username"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
style={inputStyles}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label htmlFor="password" style={{ marginBottom: '5px', display: 'block' }}>Password:</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
style={inputStyles}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type="submit" style={buttonStyles}>{isLogin ? 'Log In' : 'Register'}</button>
|
||||||
|
</form>
|
||||||
|
<button onClick={toggleAuthMode} style={toggleButtonStyles}>
|
||||||
|
{isLogin ? 'Need an account? Register' : 'Already have an account? Login'}
|
||||||
|
</button>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AuthModal;
|
||||||
122
keynest/src/components/BookingPage.css
Normal file
122
keynest/src/components/BookingPage.css
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
.dark-theme {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #000;
|
||||||
|
font-family: 'Nunito';
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark-theme h1 {
|
||||||
|
color: #242323;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark-theme p {
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.booking-form {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #000;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
color: #c6c3c3;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input {
|
||||||
|
padding: 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #000;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input:focus {
|
||||||
|
background-color: #eee;
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 0 2px #242323;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.submit-button {
|
||||||
|
background-color: #242323;
|
||||||
|
color: #fff;
|
||||||
|
padding: 14px 24px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-button:hover {
|
||||||
|
background-color: #242323;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-button:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 0 3px rgba(217, 217, 217, 0.5);
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
background-color: #F44336;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.back-to-home-button {
|
||||||
|
background-color: #242323;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-home-button:hover {
|
||||||
|
background-color: #242323;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-home-button:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: 0 0 0 3px rgba(220, 220, 220, 0.5);
|
||||||
|
}
|
||||||
105
keynest/src/components/BookingPage.js
Normal file
105
keynest/src/components/BookingPage.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import './BookingPage.css';
|
||||||
|
|
||||||
|
function BookingPage() {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
name: '',
|
||||||
|
email: '',
|
||||||
|
checkin: '',
|
||||||
|
checkout: ''
|
||||||
|
});
|
||||||
|
const [message, setMessage] = useState('');
|
||||||
|
const [isSuccess, setIsSuccess] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const checkinDate = new Date(formData.checkin);
|
||||||
|
const checkoutDate = new Date(formData.checkout);
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
if (checkinDate < today) {
|
||||||
|
setMessage('Check-in date cannot be in the past.');
|
||||||
|
setIsSuccess(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkoutDate <= checkinDate) {
|
||||||
|
setMessage('Check-out date must be after check-in date.');
|
||||||
|
setIsSuccess(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await submitForm(formData);
|
||||||
|
setMessage('Booking successful!');
|
||||||
|
setIsSuccess(true);
|
||||||
|
setFormData({ name: '', email: '', checkin: '', checkout: '' });
|
||||||
|
} catch (error) {
|
||||||
|
setMessage('Booking failed. Please try again.');
|
||||||
|
setIsSuccess(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBackToHome = () => {
|
||||||
|
navigate('/');
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitForm = (data) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="booking-page dark-theme">
|
||||||
|
<button className="back-to-home-button" onClick={handleBackToHome}>
|
||||||
|
Back to Home
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h1>Book Your Apartment Now!</h1>
|
||||||
|
<p>Please fill out the form below to complete your booking.</p>
|
||||||
|
|
||||||
|
<form className="booking-form" onSubmit={handleSubmit}>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="name">Name:</label>
|
||||||
|
<input type="text" id="name" name="name" required value={formData.name} onChange={handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="email">Email:</label>
|
||||||
|
<input type="email" id="email" name="email" required value={formData.email} onChange={handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="checkin">Check-in Date:</label>
|
||||||
|
<input type="date" id="checkin" name="checkin" required value={formData.checkin} onChange={handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="checkout">Check-out Date:</label>
|
||||||
|
<input type="date" id="checkout" name="checkout" required value={formData.checkout} onChange={handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" className="submit-button">Complete Booking</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{message && (
|
||||||
|
<div className={`message ${isSuccess ? 'success' : 'error'}`}>
|
||||||
|
{message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BookingPage;
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
.Flexible2{
|
|
||||||
left: 341px;
|
|
||||||
top: 2330px;
|
|
||||||
}
|
|
||||||
.Flexible{
|
|
||||||
left: 290px;
|
|
||||||
top: 2375px;
|
|
||||||
}
|
|
||||||
.Flexible1{
|
|
||||||
left: calc(50% - 660px/2 + 0.5px);
|
|
||||||
top: 2440px;
|
|
||||||
}
|
|
||||||
.Flexible3{
|
|
||||||
left: 290px;
|
|
||||||
top: 2545px;
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
|
||||||
import './FlexibleLeasing.css';
|
|
||||||
|
|
||||||
function FlexibleLeasing(){
|
|
||||||
return(
|
|
||||||
<header className='apartment'>
|
|
||||||
<div className='Attractions__header'>
|
|
||||||
<div className='Attractions__content'>
|
|
||||||
<p className='the__subtitle Flexible2' >Flexible Leasing</p>
|
|
||||||
<p className='heading__Amenities Flexible'>Tailor-made Leases</p>
|
|
||||||
<p className='info__Amenities Flexible1'>Choose from a variety of flexible leasing options, whether you need a short-term stay or a long-term commitment, we have the perfect solution for you</p>
|
|
||||||
</div>
|
|
||||||
<div className='img__Amenitiess1 Flexible3'>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image7.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Modern Designs</p>
|
|
||||||
<p className='img_info'>Sleek and stylish, our apartments feature contemporary designs that elevate your living experience</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image8.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Cozy Retreats</p>
|
|
||||||
<p className='img_info'>Warm and inviting, our apartments offer a private sanctuary to unwind and recharge</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image9.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Refined Elegance</p>
|
|
||||||
<p className='img_info'>Sophisticated and refined, our apartments exude an air of elegant sophistication</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FlexibleLeasing;
|
|
||||||
66
keynest/src/components/Footer.css
Normal file
66
keynest/src/components/Footer.css
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
.footer {
|
||||||
|
background-color: #333;
|
||||||
|
color: #fff;
|
||||||
|
padding: 40px 0;
|
||||||
|
font-family: 'Nunito', sans-serif;
|
||||||
|
margin-top: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-container {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-around;
|
||||||
|
top: 1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 250px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section h3 {
|
||||||
|
color: #a6a5a8;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-section p {
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-right: 15px;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social-links a:hover {
|
||||||
|
color: #bb86fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom p {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom a:hover {
|
||||||
|
color: #bb86fc;
|
||||||
|
}
|
||||||
35
keynest/src/components/Footer.js
Normal file
35
keynest/src/components/Footer.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import './Footer.css';
|
||||||
|
|
||||||
|
function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="footer">
|
||||||
|
<div className="footer-container">
|
||||||
|
<div className="footer-section">
|
||||||
|
<h3>About KeyNest</h3>
|
||||||
|
<p>KeyNest is your trusted platform for finding the perfect apartment rental. We connect renters with quality properties and exceptional service.</p>
|
||||||
|
</div>
|
||||||
|
<div className="footer-section">
|
||||||
|
<h3>Contact Us</h3>
|
||||||
|
<p>Email: info@keynest.com</p>
|
||||||
|
<p>Phone: +7 (904) 456-7890</p>
|
||||||
|
<p>Address: Oktyabrsky Prospekt 19, Syktyvkar, Russia</p>
|
||||||
|
</div>
|
||||||
|
<div className="footer-section">
|
||||||
|
<h3>Follow Us</h3>
|
||||||
|
<div className="social-links">
|
||||||
|
<a href="#" target="_blank" rel="noopener noreferrer">VKontakte</a>
|
||||||
|
<a href="#" target="_blank" rel="noopener noreferrer">Telegram</a>
|
||||||
|
<a href="#" target="_blank" rel="noopener noreferrer">WhatsApp</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="footer-bottom">
|
||||||
|
<p>© {new Date().getFullYear()} KeyNest. All rights reserved.</p>
|
||||||
|
<p><a href="/terms">Terms of Service</a> | <a href="/privacy">Privacy Policy</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Footer;
|
||||||
@@ -21,11 +21,14 @@ body{
|
|||||||
}
|
}
|
||||||
.menu {
|
.menu {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.menu a{
|
.menu a{
|
||||||
margin-right: 158px;
|
margin-right: 158px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #242323;
|
||||||
}
|
}
|
||||||
.login-button{
|
.button{
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
margin-right: 300px;
|
margin-right: 300px;
|
||||||
@@ -37,6 +40,7 @@ body{
|
|||||||
color: aliceblue;
|
color: aliceblue;
|
||||||
padding-left: 39px;
|
padding-left: 39px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo{
|
.logo{
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -1,25 +1,47 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import './Header.css';
|
import './Header.css';
|
||||||
|
import AuthModal from './AuthModal';
|
||||||
|
import { useAuth } from './AuthContext';
|
||||||
|
|
||||||
function Header(){
|
function Header() {
|
||||||
return(
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const { isLoggedIn, logout } = useAuth();
|
||||||
|
|
||||||
|
const openModal = () => {
|
||||||
|
setIsModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
setIsModalOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
logout();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
<header>
|
<header>
|
||||||
<div className='container'>
|
<div className="container">
|
||||||
<div className='logo'>
|
<div className="logo">
|
||||||
<img src={process.env.PUBLIC_URL + '/images/Logo(Nav) (1).png'} alt='изображение' />
|
<img src={process.env.PUBLIC_URL + '/images/Logo(Nav) (1).png'} alt="изображение" />
|
||||||
<span>KeyNest</span>
|
<span>KeyNest</span>
|
||||||
</div>
|
</div>
|
||||||
<nav className='menu'>
|
<nav className="menu">
|
||||||
<a>Home</a>
|
<Link to="/">Home</Link>
|
||||||
<a>About</a>
|
<Link to="/about">About</Link>
|
||||||
<a>Rentals</a>
|
<Link to="/myrentals">Rentals</Link> {/* Updated link */}
|
||||||
<a>Contact</a>
|
<Link to="/contact">Contact</Link>
|
||||||
</nav>
|
</nav>
|
||||||
<button className='login-button'>Login</button>
|
{isLoggedIn ? (
|
||||||
|
<button className="logout-button button" onClick={handleLogout}>Logout</button>
|
||||||
|
) : (
|
||||||
|
<button className="login-button button" onClick={openModal}>Login</button>
|
||||||
|
)}
|
||||||
|
<AuthModal isOpen={isModalOpen} onRequestClose={closeModal} />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
63
keynest/src/components/MyRentals.css
Normal file
63
keynest/src/components/MyRentals.css
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
.my-rentals-page {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-rentals-page h1 {
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rentals-list {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 800px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rental-item {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rental-item:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rental-item h3 {
|
||||||
|
color: #242324;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rental-item p {
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.back-to-home-button {
|
||||||
|
background-color: #242323;
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-home-button:hover {
|
||||||
|
background-color: #242323;
|
||||||
|
}
|
||||||
54
keynest/src/components/MyRentals.js
Normal file
54
keynest/src/components/MyRentals.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom'; // Import Link
|
||||||
|
import './MyRentals.css';
|
||||||
|
|
||||||
|
function MyRentals() {
|
||||||
|
const rentals = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: 'Cozy Apartment in Downtown',
|
||||||
|
location: '123 Main St, Cityville',
|
||||||
|
checkin: '2024-05-01',
|
||||||
|
checkout: '2024-05-07',
|
||||||
|
status: 'Confirmed'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: 'Luxury Condo with Ocean View',
|
||||||
|
location: '456 Ocean Ave, Beach City',
|
||||||
|
checkin: '2024-06-10',
|
||||||
|
checkout: '2024-06-17',
|
||||||
|
status: 'Pending'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: 'Modern Loft in Arts District',
|
||||||
|
location: '789 Art Lane, Culturetown',
|
||||||
|
checkin: '2024-07-01',
|
||||||
|
checkout: '2024-07-08',
|
||||||
|
status: 'Completed'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="my-rentals-page">
|
||||||
|
<Link to="/" className="back-to-home-button">
|
||||||
|
Back to Home
|
||||||
|
</Link>
|
||||||
|
<h1>My Rentals</h1>
|
||||||
|
<div className="rentals-list">
|
||||||
|
{rentals.map((rental) => (
|
||||||
|
<div key={rental.id} className="rental-item">
|
||||||
|
<h3>{rental.title}</h3>
|
||||||
|
<p>Location: {rental.location}</p>
|
||||||
|
<p>Check-in: {rental.checkin}</p>
|
||||||
|
<p>Check-out: {rental.checkout}</p>
|
||||||
|
<p>Status: {rental.status}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MyRentals;
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
.the__subtitle{
|
|
||||||
position: absolute;
|
|
||||||
width: 1180px;
|
|
||||||
height: 20px;
|
|
||||||
font-family: 'Nunito';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 120%;
|
|
||||||
text-align: center;
|
|
||||||
color: #B8B7B9;
|
|
||||||
}
|
|
||||||
.Attractions2{
|
|
||||||
left: 341px;
|
|
||||||
top: 1610px;
|
|
||||||
}
|
|
||||||
.Attractions__header{
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.Attractions{
|
|
||||||
width: 1180px;
|
|
||||||
height: 56px;
|
|
||||||
left: 347px;
|
|
||||||
top: 1645px;
|
|
||||||
color: #292729;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
.Attractions1{
|
|
||||||
padding-top: 10px;
|
|
||||||
width: 711px;
|
|
||||||
height: 81px;
|
|
||||||
left: calc(50% - 760px/2 + 0.5px);
|
|
||||||
top: 1700px;
|
|
||||||
}
|
|
||||||
.img__Amenitiess1{
|
|
||||||
position: absolute;
|
|
||||||
width: 1281px;
|
|
||||||
height: 587px;
|
|
||||||
display: flex;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
}
|
|
||||||
.Attractions3{
|
|
||||||
left: 300px;
|
|
||||||
top: 1800px;
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
|
||||||
import './NearbyAttractions.css';
|
|
||||||
|
|
||||||
function NearbyAttractions(){
|
|
||||||
return(
|
|
||||||
<header className='apartment'>
|
|
||||||
<div className='Attractions__header'>
|
|
||||||
<div className='Attractions__content'>
|
|
||||||
<p className='the__subtitle Attractions2'>Nearby Attractions</p>
|
|
||||||
<p className='heading__Amenities Attractions'>Explore the City</p>
|
|
||||||
<p className='info__Amenities Attractions1'>Discover the best of urban living with our centrally located apartments, offering easy access to top restaurants, entertainment, and cultural destinations</p>
|
|
||||||
</div>
|
|
||||||
<div className='img__Amenitiess1 Attractions3'>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image4.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Workspace Ready</p>
|
|
||||||
<p className='img_info'>Maximize productivity with our well-appointed workspaces, perfect for remote work or studying</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image5.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Peaceful Retreats</p>
|
|
||||||
<p className='img_info'>Unwind in the comfort of your own private oasis, surrounded by serene natural elements</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image6.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Luxurious Comforts</p>
|
|
||||||
<p className='img_info'>Indulge in the ultimate in comfort and style with our premium bedding and furnishings</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default NearbyAttractions;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
.Convenience4{
|
|
||||||
background-color: #E4E4E4;
|
|
||||||
}
|
|
||||||
.Convenience2{
|
|
||||||
left: 341px;
|
|
||||||
top: 2330px;
|
|
||||||
}
|
|
||||||
.Convenience{
|
|
||||||
left: 290px;
|
|
||||||
top: 3220px;
|
|
||||||
}
|
|
||||||
.Convenience1{
|
|
||||||
left: calc(50% - 660px/2 + 0.5px);
|
|
||||||
top: 3300px;
|
|
||||||
}
|
|
||||||
.Convenience3{
|
|
||||||
left: 290px;
|
|
||||||
top: 3445px;
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
|
||||||
import './UnparalleledConvenience.css';
|
|
||||||
|
|
||||||
function UnparalleledConvenience(){
|
|
||||||
return(
|
|
||||||
<header className='apartment Convenience4'>
|
|
||||||
<div className='Attractions__header'>
|
|
||||||
<div className='Attractions__content'>
|
|
||||||
<p className='heading__Amenities Convenience'>Unparalleled Convenience</p>
|
|
||||||
<p className='info__Amenities Convenience1'>Centrally located and well-connected, our apartments provide easy access to the city's top attractions, transportation hubs, and essential amenities</p>
|
|
||||||
</div>
|
|
||||||
<div className='img__Amenitiess1 Convenience3'>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image10.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Peaceful Oasis</p>
|
|
||||||
<p className='img_info'>Escape the hustle and bustle of the city in the comfort of your own private retreat</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image11.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Stylish Sanctuaries</p>
|
|
||||||
<p className='img_info'>Immerse yourself in the tranquility of our beautifully designed apartments</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img className ='img__Nearby' src={process.env.PUBLIC_URL + '/images/Image12.png'} alt='изображение' />
|
|
||||||
<p className='img_name'>Urban Sanctuaries</p>
|
|
||||||
<p className='img_info'>Discover the perfect balance of urban living and serene relaxation</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default UnparalleledConvenience;
|
|
||||||
Reference in New Issue
Block a user