Merge branch 'master' of https://github.com/ArcticHawk1/SEG3125-LAB8
|
@ -1,8 +1,10 @@
|
|||
# SEG3125-LAB8
|
||||
|
||||
The Real Estate Website using React made by Ruchira Perrera, Sam Oyediran, Batuhan Basoglu, and Kene Ojukwu
|
||||
The Real Estate Website using React made by Ruchira Perrera, Sam Oyediran, Batuhan Basoglu, and Kene Ojukwu.
|
||||
|
||||
|
||||
After npm start execute the command "node src/shared-components/contact-us/index.js" in order to set up the backend of the contact form.
|
||||
|
||||
# Authors
|
||||
|
||||
- Batuhan Basoglu, 300001274 - ArcticHawk1
|
||||
|
|
20927
package-lock.json
generated
39
package.json
|
@ -6,16 +6,38 @@
|
|||
"@testing-library/jest-dom": "^5.11.10",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^12.8.3",
|
||||
"axios": "^0.21.1",
|
||||
"bootstrap": "^4.6.0",
|
||||
"cors": "^2.8.5",
|
||||
"email-validator": "^2.0.4",
|
||||
"express": "^4.17.1",
|
||||
"flag-icon-css": "^3.5.0",
|
||||
"formik": "^2.2.6",
|
||||
"i18next": "^20.2.1",
|
||||
"i18next-browser-languagedetector": "^6.1.0",
|
||||
"i18next-http-backend": "^1.2.1",
|
||||
"joi-browser": "^13.4.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"nodemailer": "^6.5.0",
|
||||
"react": "^17.0.2",
|
||||
"react-alert": "^7.0.2",
|
||||
"react-alert-template-basic": "^1.0.0",
|
||||
"react-bootstrap": "^1.5.2",
|
||||
"react-bootstrap-carousel": "^4.1.1",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-fa": "^5.0.0",
|
||||
"react-form-with-constraints": "^0.16.0",
|
||||
"react-form-with-constraints-bootstrap4": "^0.16.0",
|
||||
"react-google-maps": "^9.4.5",
|
||||
"react-hook-form": "^7.0.0",
|
||||
"react-i18next": "^11.8.12",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "4.0.3",
|
||||
"react-select": "^4.3.0",
|
||||
"reactstrap": "^8.9.0",
|
||||
"spectre.css": "^0.5.9",
|
||||
"web-vitals": "^1.1.1"
|
||||
"web-vitals": "^1.1.1",
|
||||
"yup": "^0.32.9"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
@ -43,5 +65,18 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"create-react-component-folder": "^0.3.7"
|
||||
}
|
||||
},
|
||||
"description": "The Real Estate Website using React made by Ruchira Perrera, Sam Oyediran, Batuhan Basoglu, and Kene Ojukwu.",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ArcticHawk1/SEG3125-LAB8.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ArcticHawk1/SEG3125-LAB8/issues"
|
||||
},
|
||||
"homepage": ""
|
||||
}
|
||||
|
|
56
public/assets/locales/en/translations.json
Normal file
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"Welcome_to_React": "Welcome to React and react-i18next",
|
||||
"Login_header": "Kene's Cribs",
|
||||
"Login_message": "Welcome please back, please sign in!",
|
||||
"Login_email": "Email address",
|
||||
"Login_password": "Password",
|
||||
"Login_remember_me": "remember me",
|
||||
"Login_submit_button": "Submit",
|
||||
"Account_header": "Personal Information",
|
||||
"Account_message": "You can update/edit your account information here",
|
||||
"Account_first_name": "First Name",
|
||||
"Account_last_name": "Last Name",
|
||||
"Account_email": "Email",
|
||||
"Account_phone_number": "Phone Number",
|
||||
"Account_current_password": "Current Password",
|
||||
"Account_new_password": "New password",
|
||||
"Account_update_button": "Update",
|
||||
"Footer_message": "Copyright SEG3125 - Group 3",
|
||||
"Nav_brand": "Kene's Cribs",
|
||||
"Nav_Home": "Home",
|
||||
"Nav_Listings": "Listings",
|
||||
"Nav_Agents": "Agents",
|
||||
"Nav_Contact_Us": "Contact Us",
|
||||
"Nav_listing_page": "listing-page",
|
||||
"Nav_Login": "Login",
|
||||
"Slogan_1": "YOU ARE NOT BUYING A HOUSE, ",
|
||||
"Slogan_2": "YOU ARE BUYING A LIFESTYLE. ",
|
||||
"Info": "Click for Details",
|
||||
"Home1": "Welcome to Kene's Cribs. Kene's Cribs is a real estator company which provides the clients with the houses.",
|
||||
"Home2": "The houses limited to the clients are only limited to the clients' dreams. In order to further navigate the",
|
||||
"Home3": "website, use the navigation bar to switch between pages. Listings page is for browsing houses, Agents page",
|
||||
"Home4": "is for browsing the estators, the Contact Us page is for the contacting us and the login page is for our",
|
||||
"Home5": "members who want to benefit from our deals. Above are some houses which can interest you. Feel free to",
|
||||
"Home6": "click the buttons above to explore the houses you want.",
|
||||
"Desc": "Description",
|
||||
"Rooms": "1 Bedroom, 2 Bathroom",
|
||||
"Danger1": "Message could not send.",
|
||||
"Danger2": "There are some errors in your contact form.",
|
||||
"Success1": "The message is successfully sent.",
|
||||
"Success2": "You contact form will be delivered to our support team.",
|
||||
"Contact-Title": "Contact to Us",
|
||||
"Contact-House": "Select an Agent",
|
||||
"Contact-Agent": "Select a House",
|
||||
"No-Pref": "No preference",
|
||||
"Contact-First": "First Name",
|
||||
"Contact-Last": "Last Name",
|
||||
"Contact-Mail": "Email Address",
|
||||
"Contact-Message": "Message",
|
||||
"Contact-Submit": "Submit",
|
||||
"Contact-Error1": "Please select an item in the list.",
|
||||
"Contact-Error2": "Please fill out this field.",
|
||||
"Contact-Error3": "Invalid email address."
|
||||
|
||||
|
||||
|
||||
}
|
53
public/assets/locales/fr/translations.json
Normal file
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"Welcome_to_React": "Bienvenue a react et react-i18next",
|
||||
"Login_header": "Berceaux de Kene",
|
||||
"Login_message": "Bienvenue, merci de vous connecter!",
|
||||
"Login_email": "Adresse e-mail",
|
||||
"Login_password": "Mot de passe",
|
||||
"Login_remember_me": "souviens-toi de moi",
|
||||
"Login_submit_button": "Nous faire parvenir",
|
||||
"Account_header": "Informations personnelles",
|
||||
"Account_message": "Vous pouvez mettre à jour / modifier les informations de votre compte ici",
|
||||
"Account_first_name": "Prénom",
|
||||
"Account_last_name": "Nom de famille",
|
||||
"Account_email": "E-mail",
|
||||
"Account_phone_number": "Numéro de téléphone",
|
||||
"Account_current_password": "Mot de passe actuel",
|
||||
"Account_new_password": "Nouveau mot de passe",
|
||||
"Account_update_button": "Mettre à jour",
|
||||
"Footer_message": "Copyright SEG3125 - Groupe 3",
|
||||
"Nav_brand": "Berceaux de Kene",
|
||||
"Nav_Home": "Accueil",
|
||||
"Nav_Listings": "Annonces",
|
||||
"Nav_Agents": "Agents",
|
||||
"Nav_Contact_Us": "Nous contacter",
|
||||
"Nav_listing_page": "page de liste",
|
||||
"Nav_Login": "Connexion",
|
||||
"Slogan_1": "VOUS N'ACHETEZ PAS UNE MAISON, ",
|
||||
"Slogan_2": "VOUS ACHETEZ UN STYLE DE VIE. ",
|
||||
"Info": "Cliquer pour les détails",
|
||||
"Home1": "Bienvenue chez Kene's Cribs. Kene's Cribs est une véritable société d'estateur qui fournit les maisons aux clients.",
|
||||
"Home2": "Les maisons limitées aux clients ne se limitent qu'aux rêves des clients. Afin de mieux naviguer dans site Web, utilisez",
|
||||
"Home3": "la barre de navigation pour basculer entre les pages. La page des listes sert à parcourir les maisons, la page Agents",
|
||||
"Home4": "est pour parcourir les estators, la page Contactez-nous est pour nous contacter et la page de connexion est pour notre",
|
||||
"Home5": "membres qui souhaitent bénéficier de nos offres. Ci-dessus, quelques maisons qui peuvent vous intéresser. N'hésitez",
|
||||
"Home6": "pas à cliquez sur les boutons ci-dessus pour explorer les maisons que vous souhaitez.",
|
||||
"Desc": "La Description",
|
||||
"Rooms": "1 chambre, 2 salles de bains",
|
||||
"Danger1": "Le message n'a pas pu être envoyé.",
|
||||
"Danger2": "Il y a des erreurs dans votre formulaire de contact.",
|
||||
"Success1": "Le message a été envoyé avec succès.",
|
||||
"Success2": "Votre formulaire de contact sera envoyé à notre équipe d'assistance.",
|
||||
"Contact-Title": "Contactez-Nous",
|
||||
"Contact-House": "Sélectionnez un Agent",
|
||||
"Contact-Agent": "Sélectionnez une Maison",
|
||||
"No-Pref": "Aucune préférence",
|
||||
"Contact-First": "Prénom",
|
||||
"Contact-Last": "Nom de Famille",
|
||||
"Contact-Mail": "Adresse E-mail",
|
||||
"Contact-Message": "Le Message",
|
||||
"Contact-Submit": "Soumettre",
|
||||
"Contact-Error1": "Veuillez sélectionner un élément dans la liste.",
|
||||
"Contact-Error2": "Veuillez remplir ce champ.",
|
||||
"Contact-Error3": "Adresse e-mail invalide."
|
||||
}
|
|
@ -57,7 +57,7 @@
|
|||
|
||||
<title>Kene's Cribs</title>
|
||||
</head>
|
||||
<body>
|
||||
<body dir="ltr">
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
|
|
92
src/App.js
|
@ -1,26 +1,90 @@
|
|||
import { Component } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import Footer from "./shared-components/footer-component/Footer";
|
||||
import Navbar from "./shared-components/navbar-component/Navbar";
|
||||
import { BrowserRouter, Route } from "react-router-dom";
|
||||
import { BrowserRouter, Route, Switch } from "react-router-dom";
|
||||
import i18next from "i18next";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Cookies from "js-cookie";
|
||||
import HomePage from "./homePage/Homepage";
|
||||
import ListingsPage from "./listings-page/ListingsPage";
|
||||
import AgentPage from "./agent-page/AgentPage";
|
||||
// import ContactUs from "./shared-components/Contact-us/Contact-us";
|
||||
import ListingPage from "./listings-page/single-listing/listing-page";
|
||||
import Login from "./login-page/Login";
|
||||
import Account from "./login-page/account/Account";
|
||||
import ContactUs from "./shared-components/contact-us/contact-us";
|
||||
|
||||
class App extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="App">
|
||||
<BrowserRouter>
|
||||
<Navbar></Navbar>
|
||||
const langauges = [
|
||||
{
|
||||
code: "fr",
|
||||
name: "Français",
|
||||
country_code: "fr",
|
||||
},
|
||||
{
|
||||
code: "en",
|
||||
name: "English",
|
||||
country_code: "gb",
|
||||
},
|
||||
];
|
||||
|
||||
function App() {
|
||||
const currentLanguageCode = Cookies.get("i18next") || "en";
|
||||
const currentLanguage = langauges.find(
|
||||
(lang) => lang.code === currentLanguageCode
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.body.dir = currentLanguage.dir || "ltr";
|
||||
}, [currentLanguage]);
|
||||
return (
|
||||
<div className="App">
|
||||
{/* create the translations button */}
|
||||
<div className="container">
|
||||
<div className="d-flex justify-content-end">
|
||||
{/* <!-- Example single danger button --> */}
|
||||
<div class="btn-group">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i class="fas fa-globe"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
{langauges.map(({ code, name, country_code }) => (
|
||||
<button
|
||||
class="dropdown-item"
|
||||
key={code}
|
||||
onClick={() => i18next.changeLanguage(code)}
|
||||
disabled={code === currentLanguageCode}
|
||||
>
|
||||
<span
|
||||
className={`flag-icon flag-icon-${country_code} mx-2`}
|
||||
></span>
|
||||
{name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BrowserRouter>
|
||||
<Navbar></Navbar>
|
||||
<Switch>
|
||||
<Route exact path="/" component={HomePage}></Route>
|
||||
<Route path="/listings" component={ListingsPage}></Route>
|
||||
<Route path="/agents" component={AgentPage}></Route>
|
||||
</BrowserRouter>
|
||||
<Footer></Footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
<Route path="/listing-page" component={ListingPage}></Route>
|
||||
<Route path="/login" component={Login}></Route>
|
||||
<Route path="/contact-us" component={ContactUs}></Route>
|
||||
<Route path="/account" component={Account}></Route>
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
<Footer></Footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
|
@ -4,25 +4,30 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
.white-section {
|
||||
background-color: #ffffff;
|
||||
padding-top: 10rem;
|
||||
padding-bottom: 5rem;
|
||||
padding-left: 18%;
|
||||
}
|
||||
|
||||
#title .container-fluid {
|
||||
padding: 4% 34% 6%;
|
||||
padding: 5% 34% 6%;
|
||||
text-align: left;
|
||||
font-family: "Georgia";
|
||||
}
|
||||
|
||||
#features .container-fluid {
|
||||
padding: 2% 48% 2%;
|
||||
padding: 2% 14% 4%;
|
||||
text-align: left;
|
||||
font-family: "Georgia";
|
||||
}
|
||||
|
||||
|
||||
.housesIntro{
|
||||
padding: 4% 5%;
|
||||
width: 1200px;
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
.contactIntro{
|
||||
|
@ -31,23 +36,9 @@
|
|||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.carouselSection {
|
||||
margin: 2% 8%;
|
||||
}
|
||||
|
||||
.headerImg{
|
||||
width: 2000px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.heading-1{
|
||||
padding-left: 40%;
|
||||
padding-top: 10%;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.formhelper{
|
||||
padding-bottom: 15px;
|
||||
width: 1200px;
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
.button-1 {
|
||||
|
@ -67,3 +58,69 @@
|
|||
padding-left: 45%;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.buttonka{
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.prev-icon,
|
||||
.next-icon {
|
||||
height: 210px;
|
||||
width: 100px;
|
||||
outline: black;
|
||||
background-size: 100%, 100%;
|
||||
border-radius: 50%;
|
||||
background-image: none;
|
||||
text-shadow: 2px 2px 5px black;
|
||||
}
|
||||
|
||||
.next-icon:after
|
||||
{
|
||||
content: '>';
|
||||
font-size: 140px;
|
||||
color: rgb(255, 255, 255);
|
||||
text-shadow: 2px 2px 5px black;
|
||||
}
|
||||
|
||||
.prev-icon:after {
|
||||
content: '<';
|
||||
font-size: 140px;
|
||||
color: rgb(255, 255, 255);
|
||||
text-shadow: 2px 2px 5px black;
|
||||
}
|
||||
|
||||
ol.carousel-indicators {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
margin: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
ol.carousel-indicators li,
|
||||
ol.carousel-indicators li.active {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
margin: 0;
|
||||
border-radius: 50%;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
box-shadow: 0 0 1px 1px black;
|
||||
}
|
||||
|
||||
ol.carousel-indicators li {
|
||||
background: rgb(255, 255, 255);
|
||||
margin-left: .5rem;
|
||||
margin-right: .5rem;
|
||||
box-shadow: 0 0 1px 1px black;
|
||||
}
|
||||
|
||||
ol.carousel-indicators li.active {
|
||||
background: #17a2b8;
|
||||
box-shadow: 0 0 1px 1px black;
|
||||
}
|
||||
|
||||
.homePage{
|
||||
padding-bottom: 15%;
|
||||
}
|
|
@ -3,124 +3,101 @@ import "./Homepage.css";
|
|||
import house1 from "../images/house1.jpg";
|
||||
import house2 from "../images/house2.jpg";
|
||||
import house3 from "../images/house3.jpg";
|
||||
import house4 from "../images/house4.jpg";
|
||||
import Carousel from "react-bootstrap/Carousel";
|
||||
import Button from "react-bootstrap/Button";
|
||||
import { withTranslation } from "react-i18next";
|
||||
|
||||
|
||||
|
||||
class Homepage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
firstname: "",
|
||||
lastname: "",
|
||||
email: "",
|
||||
message: "",
|
||||
nextIcon: <span className="next-icon"></span>,
|
||||
prevIcon: <span className="prev-icon"></span>,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { nextIcon, prevIcon } = this.state;
|
||||
return (
|
||||
<div className="homePage">
|
||||
<section className="colored-section" id="title">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<h1 className="big-heading">YOU ARE NOT BUYING A HOUSE, </h1>
|
||||
<h1 className="big-heading">YOU ARE BUYING A LIFESTYLE. </h1>
|
||||
<h1 className="big-heading">{t("Slogan_1")}</h1>
|
||||
<h1 className="big-heading">{t("Slogan_2")}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="white-section" id="white-section">
|
||||
<section className="white-section">
|
||||
<div className="housesIntro">
|
||||
<Carousel>
|
||||
<Carousel nextIcon={nextIcon} prevIcon={prevIcon}>
|
||||
<Carousel.Item>
|
||||
<img className="headerImg" src={house1} alt="First House" />
|
||||
<Carousel.Caption>
|
||||
<h3 style={{ fontSize: "250%", textShadow: "-2px 0 black, 0 2px black, 2px 0 black, 0 -2px black" }}>100 Charlie Rogers, Kanata, ON K2V 1A7</h3>
|
||||
<h2 style={{ fontSize: "150%", textShadow: "-2px 0 black, 0 2px black, 2px 0 black, 0 -2px black" }}>{t("Rooms")}</h2>
|
||||
<div className="buttonka">
|
||||
<Button href="/listings" variant="info">{t("Info")}</Button>
|
||||
</div>
|
||||
</Carousel.Caption>
|
||||
</Carousel.Item>
|
||||
<Carousel.Item>
|
||||
<img className="headerImg" src={house2} alt="Second House" />
|
||||
<Carousel.Caption>
|
||||
<h3 style={{ fontSize: "250%", textShadow: "-2px 0 black, 0 2px black, 2px 0 black, 0 -2px black" }}>1490 Youville Drive, Orléans, ON K1C 2X8</h3>
|
||||
<h2 style={{ fontSize: "150%", textShadow: "-2px 0 black, 0 2px black, 2px 0 black, 0 -2px black" }}>{t("Rooms")}</h2>
|
||||
<div className="buttonka">
|
||||
<Button href="/listings" variant="info">{t("Info")}</Button>
|
||||
</div>
|
||||
</Carousel.Caption>
|
||||
</Carousel.Item>
|
||||
<Carousel.Item>
|
||||
<img className="headerImg" src={house3} alt="Third House" />
|
||||
<Carousel.Caption>
|
||||
<h3 style={{ fontSize: "250%", textShadow: "-2px 0 black, 0 2px black, 2px 0 black, 0 -2px black" }}>8720 Russell Road, Navan, ON K4B 1J1</h3>
|
||||
<h2 style={{ fontSize: "150%", textShadow: "-2px 0 black, 0 2px black, 2px 0 black, 0 -2px black" }}>{t("Rooms")}</h2>
|
||||
<div className="buttonka">
|
||||
<Button href="/listings" variant="info">{t("Info")}</Button>
|
||||
</div>
|
||||
</Carousel.Caption>
|
||||
</Carousel.Item>
|
||||
<Carousel.Item>
|
||||
<img className="headerImg" src={house4} alt="Fourth House" />
|
||||
<Carousel.Caption>
|
||||
<h3 style={{ fontSize: "250%", textShadow: "-2px 0 black, 0 2px black, 2px 0 black, 0 -2px black" }}>2785 8th Line Road, Metcalfe, ON K0A 2P0</h3>
|
||||
<h2 style={{ fontSize: "150%", textShadow: "-2px 0 black, 0 2px black, 2px 0 black, 0 -2px black" }}>{t("Rooms")}</h2>
|
||||
<div className="buttonka">
|
||||
<Button href="/listings" variant="info">{t("Info")}</Button>
|
||||
</div>
|
||||
</Carousel.Caption>
|
||||
</Carousel.Item>
|
||||
</Carousel>
|
||||
</div>
|
||||
</section>
|
||||
<section class="colored-section" id="contact">
|
||||
<div className="container-fluid">
|
||||
<div className="contactIntro">
|
||||
<h2 className="heading-1">Contact Us</h2>
|
||||
<form
|
||||
id="contact-form"
|
||||
onSubmit={this.handleSubmit.bind(this)}
|
||||
method="POST"
|
||||
>
|
||||
<div className="formhelper row">
|
||||
<div className="col-6">
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="First Name"
|
||||
value={this.state.firstname}
|
||||
onChange={this.onFirstNameChange.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder="Last Name"
|
||||
value={this.state.lastname}
|
||||
onChange={this.onLastNameChange.bind(this)}
|
||||
/>
|
||||
<section className="colored-section" id="features">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<h2 style={{ paddingLeft: "22rem", paddingBottom: "1rem", fontFamily: "Trebuchet MS" }}>{t("Desc")}</h2>
|
||||
<p style={{ fontSize: "110%" }}>{t("Home1")}<br></br>
|
||||
{t("Home2")}<br></br>
|
||||
{t("Home3")}<br></br>
|
||||
{t("Home4")}<br></br>
|
||||
{t("Home5")}<br></br>
|
||||
{t("Home6")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input
|
||||
type="email"
|
||||
className="form-control"
|
||||
placeholder="Email Address"
|
||||
aria-describedby="emailHelp"
|
||||
value={this.state.email}
|
||||
onChange={this.onEmailChange.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<textarea
|
||||
className="form-control"
|
||||
placeholder="Message"
|
||||
rows="5"
|
||||
value={this.state.message}
|
||||
onChange={this.onMessageChange.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
<div className="buttonhelper">
|
||||
<button type="submit" className="button-1">
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
onFirstNameChange(event) {
|
||||
this.setState({ firstname: event.target.value });
|
||||
}
|
||||
|
||||
onLastNameChange(event) {
|
||||
this.setState({ lastname: event.target.value });
|
||||
}
|
||||
|
||||
onEmailChange(event) {
|
||||
this.setState({ email: event.target.value });
|
||||
}
|
||||
|
||||
onMessageChange(event) {
|
||||
this.setState({ message: event.target.value });
|
||||
}
|
||||
|
||||
handleSubmit(event) {}
|
||||
}
|
||||
|
||||
export default Homepage;
|
||||
export default withTranslation()(Homepage);
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
import HomePage from "./homePage";
|
||||
|
||||
describe("HomePage", () => {
|
||||
test("matches snapshot", () => {
|
||||
const wrapper = shallow(<HomePage />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
BIN
src/images/house1-2.jpg
Normal file
After Width: | Height: | Size: 247 KiB |
BIN
src/images/house1-3.jpg
Normal file
After Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 253 KiB |
BIN
src/images/house2-2.jpg
Normal file
After Width: | Height: | Size: 199 KiB |
BIN
src/images/house2-3.jpg
Normal file
After Width: | Height: | Size: 284 KiB |
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 245 KiB |
BIN
src/images/house3-2.png
Normal file
After Width: | Height: | Size: 714 KiB |
BIN
src/images/house3-3.jpg
Normal file
After Width: | Height: | Size: 229 KiB |
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 288 KiB |
BIN
src/images/house4-2.jpg
Normal file
After Width: | Height: | Size: 254 KiB |
BIN
src/images/house4-3.jpg
Normal file
After Width: | Height: | Size: 361 KiB |
BIN
src/images/house4.jpg
Normal file
After Width: | Height: | Size: 114 KiB |
BIN
src/images/profile-picture.png
Normal file
After Width: | Height: | Size: 19 KiB |
47
src/index.js
|
@ -1,14 +1,49 @@
|
|||
import React from "react";
|
||||
import React, { Suspense } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
import "flag-icon-css/css/flag-icon.min.css";
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
import HttpApi from "i18next-http-backend";
|
||||
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
|
||||
i18n
|
||||
.use(initReactI18next) // passes i18n down to react-i18next
|
||||
.use(LanguageDetector)
|
||||
.use(HttpApi)
|
||||
.init({
|
||||
// lng: "en",
|
||||
supportedLngs: ["en", "fr"],
|
||||
fallbackLng: "en",
|
||||
detection: {
|
||||
// "querystring",
|
||||
order: ["cookie", "htmlTag", "localStorage", "path", "subdomain"],
|
||||
caches: ["cookie"],
|
||||
},
|
||||
backend: {
|
||||
loadPath: "/assets/locales/{{lng}}/translations.json",
|
||||
},
|
||||
|
||||
react: {
|
||||
useSuspense: false,
|
||||
},
|
||||
});
|
||||
|
||||
const loadingMsg = (
|
||||
<div className="py-4 text-center">
|
||||
<h2>Loading......</h2>
|
||||
</div>
|
||||
);
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
<Suspense fallback={loadingMsg}>
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
</Suspense>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
|
||||
],
|
||||
"DESC":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui.",
|
||||
|
||||
"FULL_DESCRIPTION": "RUN DON'T WALK to this beautiful former Jayman show home. This home has every feature and convenience you could want in a home. When you enter you will be greeted with a large entry way, open concept main floor with a very spacious chef-like kitchen, the big eat in dinning area is an entertainers dream and plenty of room in the living room as to cozy up to the fireplace. When you head upstairs the owner 's suite will impress with a gorgeous ensuite consisting of a large soaker tub, oversized shower, separate vanities, in-floor heating and 2 separate closest. You will also find a nice sized flex room, spacious laundry room up stairs, 4 piece main bathroom and 2 more bedrooms. Then head downstairs where you will find another bedroom, bathroom and Theatre room with wet bar and beverage station that is perfect for any movie lover. Must not forget that this home is air conditioned, has front and back irrigation outside and speakers throughout the house. All of this can be yours in the lake community of Auburn Bay close to all amenities and year round lake access just a short distance away",
|
||||
"FOR_SALE": true,
|
||||
"coordinates": [-75.3372987731628, 45.383321536272049]
|
||||
"coordinates": [-75.3372987731628, 45.383321536272049],
|
||||
"BEDROOM": "2",
|
||||
"BATHROOM": "4"
|
||||
|
||||
},
|
||||
|
||||
|
@ -32,8 +34,11 @@
|
|||
|
||||
],
|
||||
"DESC":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui.",
|
||||
"FULL_DESCRIPTION": "Nature at its Finest The Shores of Toney Bay are located at the mouth of River Phillip where it meets the Northumberland Straight with direct access to the incredible recreational waterways of River Phillip and nature rich Toney Bay. This nature lovers paradise boasts a plethora of migratory bird life and the rich fish stock of River Philip. The warm waters of the Northumberland Straight are swimmable from your shorefront, easy access to year-around activities and close proximity to the quaint community of Pugwash make this an ideal spot for a permeant residence or cottage. There are also ocean view / deeded access lots available. Large lots with unobstructed views and well away from highway noise. Swim in the warm waters at beautiful Heather's Beach just 4km away, fly fishing in the spring on River Phillip, book at tee time at Northumberland links, 16km away or enjoy a day at the Luxury Fox Harb'r Resort and Spa less then 30 mins away, and in winter enjoy skiing at Ski Wentworth a short 30 minutes drive. Lots are flat, cleared and ready for your dream home. All septic and building lot approvals are in place, good roads, and power to the lot line are included. Please take a few minutes to watch the video of the stunning Shores at Toney Bay",
|
||||
"FOR_SALE": true,
|
||||
"coordinates": [-75.546518086577947, 45.467134581917357]
|
||||
"coordinates": [-75.546518086577947, 45.467134581917357],
|
||||
"BEDROOM": "7",
|
||||
"BATHROOM": "4"
|
||||
|
||||
|
||||
|
||||
|
@ -52,9 +57,11 @@
|
|||
|
||||
],
|
||||
"DESC":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui.",
|
||||
|
||||
"FULL_DESCRIPTION": "Custom, Hi-Ranch home located in sought after neighborhood in the Heart of Petawawa. This home features 2+1 bedrooms and 4 bathrooms. Main level features spacious foyer, hardwood staircase, gleaming hardwood floors and open concept living. Large windows provide lots of natural light, vaulted ceilings in living room, a spectacular spacious kitchen with stainless steel appliances and large island. Master bedroom with walk through closet and 3 piece en-suite with custom tile shower and heated tile floor. Lower level features a finished rec room with cozy gas fireplace, bedroom and 3 piece bathroom. Patio door in foyer leads to large private backyard with no rear neighbours, spacious wood deck and hot tub. Double attached garage completes the package. Pack your backs and move right in! No Conveyances of offers until Friday April 9th at 3PM however the seller has the right to view and may accept pre-emptive offers",
|
||||
"FOR_SALE": true,
|
||||
"coordinates": [-75.898610599532319, 45.295014379864874]
|
||||
"coordinates": [-75.898610599532319, 45.295014379864874],
|
||||
"BEDROOM": "2",
|
||||
"BATHROOM": "4"
|
||||
|
||||
|
||||
|
||||
|
@ -73,9 +80,12 @@
|
|||
|
||||
],
|
||||
"DESC":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui.",
|
||||
|
||||
"FULL_DESCRIPTION": "Nestled in a quiet cul-de-sac in the family-friendly Ski Club/Widdifield neighbourhood, is 62 Riddle Court, a hidden gem that has everything you've been searching for - inside and out! Look up and take in the picturesque views of the escarpment, take a short walk or drive to the Laurentian Ski Hill with the family, or simply savour your very own property by having dinner on the patio, a glass of wine on the deck/balcony, and admire the breathtaking landscape (designed by an award-winning landscape artist) that wraps around your home. Lush perennials, tall grasses, interlocking brick pathways, in-ground sprinkler system and outdoor lighting make this property standout from the rest! Step inside to relish in all of the updated features this home has to offer - gleaming maple hardwood floors & stairs, updated maple kitchen cabinets, ceramic tile with in-floor radiant heat in bathrooms and office, built-in entertainment units, finished laundry room, low-maintenance composite deck off dining area, recessed lighting, updated windows, doors, insulation... the list goes on! Working from home these days? Enter the private & professional home office right off the recreation room through french doors. Enjoy the under-cabinet lighting, as well as the natural light beaming through the window with views of the backyard. Pride of ownership is obvious. Nothing left to do, but move-in! Pre-inspected for your peace of mind.",
|
||||
"FOR_SALE": true,
|
||||
"coordinates": [-75.468561642270757, 45.23032561834377]
|
||||
"coordinates": [-75.468561642270757, 45.23032561834377],
|
||||
"BEDROOM": "4",
|
||||
"BATHROOM": "3"
|
||||
|
||||
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
.single-listing{
|
||||
padding: 7% 15%;
|
||||
/* background-color: darksalmon; */
|
||||
}
|
||||
|
||||
.listing-header{
|
||||
border: 1px solid black;
|
||||
text-align: left;
|
||||
padding: 1%;
|
||||
}
|
||||
.listing-title{
|
||||
font-size: 2.5rem;
|
||||
/* font-style: italic; */
|
||||
}
|
||||
|
||||
.title-icon{
|
||||
|
||||
}
|
||||
|
||||
.listing-carousel{
|
||||
margin: 5% 15%;
|
||||
width: 70%;
|
||||
/* padding-right: 10; */
|
||||
}
|
||||
|
||||
.carousel-img{
|
||||
/* width: 70%; */
|
||||
}
|
||||
|
||||
|
||||
.amentities{
|
||||
border: 1px solid black;
|
||||
/* padding: 5% 0; */
|
||||
margin: 3% 40%;
|
||||
padding: 1% 0%;
|
||||
}
|
||||
.amentities-text{
|
||||
|
||||
}
|
||||
.amentities-icon{
|
||||
margin: 0% 5%;
|
||||
}
|
||||
|
||||
.description-box{
|
||||
border: 1px solid black;
|
||||
padding: 5%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.description-title{
|
||||
padding: 2% 0%;
|
||||
}
|
||||
.listing-description{
|
||||
|
||||
|
||||
}
|
||||
|
||||
.booking-btn{
|
||||
padding: 2% 0%;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -1,9 +1,139 @@
|
|||
import React, { Component } from "react";
|
||||
import React from "react";
|
||||
import "./listing-page.css";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
class ListingPage extends Component {
|
||||
render() {
|
||||
return <div>ListingPage</div>;
|
||||
}
|
||||
}
|
||||
// import house images
|
||||
import house_img1 from "../../images/house1-2.jpg";
|
||||
const ListingPage = () => {
|
||||
return (
|
||||
<div className="single-listing">
|
||||
{/* Listing header */}
|
||||
<div className="row listing-header">
|
||||
<div className="col-12">
|
||||
<h2 className="listing-title">
|
||||
<i class="fas fa-home title-icon"></i> My title
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Carousel for images of the listings */}
|
||||
<div className="listing-carousel">
|
||||
<div
|
||||
id="carouselExampleControls"
|
||||
class="carousel slide"
|
||||
data-ride="carousel"
|
||||
>
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active carousel-img">
|
||||
<img
|
||||
src={house_img1}
|
||||
class="d-block w-100"
|
||||
alt="listing-img"
|
||||
></img>
|
||||
</div>
|
||||
<div class="carousel-item carousel-img">
|
||||
<img
|
||||
src={house_img1}
|
||||
class="d-block w-100"
|
||||
alt="listing-img"
|
||||
></img>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<img
|
||||
src={house_img1}
|
||||
class="d-block w-100"
|
||||
alt="listing-img"
|
||||
></img>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
class="carousel-control-prev"
|
||||
href="#carouselExampleControls"
|
||||
role="button"
|
||||
data-slide="prev"
|
||||
>
|
||||
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
||||
<span class="sr-only">Previous</span>
|
||||
</a>
|
||||
<a
|
||||
class="carousel-control-next"
|
||||
href="#carouselExampleControls"
|
||||
role="button"
|
||||
data-slide="next"
|
||||
>
|
||||
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
||||
<span class="sr-only">Next</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Text box for listing amenities */}
|
||||
<div className="amentities">
|
||||
<span className="amentities-text">1</span>
|
||||
<i class="fas fa-bed fa-2x amentities-icon"></i>
|
||||
<span className="amentities-text">2</span>
|
||||
<i class="fas fa-bath fa-2x amentities-icon"></i>
|
||||
<span className="amentities-text">3</span>
|
||||
<i class="fas fa-wifi fa-2x amentities-icon"></i>
|
||||
</div>
|
||||
|
||||
{/* Description for the listing */}
|
||||
<div className="description-box">
|
||||
<h2 className="description-title">Description</h2>
|
||||
<p className="listing-description">
|
||||
MOVE IN READY I WALKING DISTANCE TO SHOPPING, SCHOOLS AND TRANSIT I
|
||||
Conveniently located in Haysboro, you have Restaurants, Groceries,
|
||||
Coffee shops, Schools and a Library all within walking distance. This
|
||||
Updated Bungalow offers over 2000 square feet of developed living
|
||||
space, 3 Bedrooms upstairs to accommodate almost any family and 2 down
|
||||
stairs in the fully developed basement. Having a separate entrance
|
||||
downstairs through the backyard makes it much easier if you ever want
|
||||
to convert the basement into a suite. The double garage is even heated
|
||||
with 220v plus 2 additional spaces that could be used for RV parking
|
||||
or for any additional vehicles in the house. You will notice the home
|
||||
has been tastefully updated over the years including a soaker tub in
|
||||
the bathroom, in the kitchen your cabinetry goes right to the ceiling
|
||||
for a nice finished look, granite counters and Kitchenaid appliances
|
||||
and a new garburator. The entire property has a fresh coat of paint
|
||||
inside and out, Newer windows and roof along with the Plumbing,
|
||||
Electrical (Cat 5 connection throughout and 200amp service) has been
|
||||
updated. Last but not least, the back deck already has gas and ready
|
||||
for the BBQ season. With the BIG updates being done, all that is left
|
||||
to do is enjoy Summer on the deck or enjoy a bonfire in your sunny
|
||||
West facing backyard!
|
||||
</p>
|
||||
<div className="booking-btn">
|
||||
<Link to="/contact-us">
|
||||
<button type="button" class="btn btn-lg btn-info">
|
||||
Book Showing
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// sources for the images used
|
||||
//images.adsttc.com/media/images/524c/2511/e8e4/4e67/bf00/03c3/large_jpg/Tetris_House_03.jpg?1380721927
|
||||
|
||||
//House description
|
||||
// ->Link 1 -https://www.realtor.ca/real-estate/23018057/9811-elbow-drive-calgary-haysboro
|
||||
// images
|
||||
// 1 ->house1.jpg
|
||||
// 2 ->//images.adsttc.com/media/images/524c/2511/e8e4/4e67/bf00/03c3/large_jpg/Tetris_House_03.jpg?1380721927
|
||||
// 3 ->https://s3.amazonaws.com/on1-wp/wp-content/uploads/2018/08/3191-NW-Jenna-22-of-49v2-1024x683.jpg
|
||||
//-> Link2 -> https://www.realtor.ca/real-estate/23020015/lot-14-67-seastone-drive-port-howe-port-howe
|
||||
// 1 ->house2.jpg
|
||||
// 2 ->https://static.photocdn.pt/images/articles/2019/12/24/How_to_Take_Gorgeous_Interior_Real_Estate_Photos.jpg
|
||||
// 3 ->https://i.pinimg.com/originals/f3/72/87/f372870f4f99d3278193a3970aa394ce.jpg
|
||||
//->Link3 -> https://www.realtor.ca/real-estate/23020040/1035-butler-boulevard-petawawa-laurentian-highlands
|
||||
// 1 ->house3.jpg
|
||||
// 2 ->https://miro.medium.com/max/1200/1*EyGqOwy0wQwKHUgi3xpQZA.png
|
||||
// 3 ->https://i.pinimg.com/originals/9b/fe/76/9bfe76b23f7ed9dcb35f7553b8255f48.jpg
|
||||
//->Link4 -> https://www.realtor.ca/real-estate/23020103/62-riddle-court-north-bay
|
||||
// 1 ->house4.jpg
|
||||
// 2 ->https://pictureitsoldfl.com/wp-content/uploads/2016/07/305-Rudder-Cay-Way-Jupiter-FL-print-014-28-Family-Room-4200x2800-300dpi-1170x780.jpg
|
||||
// 3 ->https://www.tlcinteriors.com.au/wp-content/uploads/2018/06/hamptons-style-kitchen-from-metricon-bayville-display-home.jpg
|
||||
|
||||
export default ListingPage;
|
||||
|
|
26
src/login-page/Login.css
Normal file
|
@ -0,0 +1,26 @@
|
|||
.login-page{
|
||||
padding: 10% 30%;
|
||||
text-align: center;
|
||||
background-color: pink;
|
||||
|
||||
}
|
||||
.signin-Form{
|
||||
border: 1px solid blanchedalmond;
|
||||
border-radius: 2%;
|
||||
}
|
||||
|
||||
.hr{
|
||||
border-top: 2px dashed beige;
|
||||
width: 30%;
|
||||
}
|
||||
.app-logo{
|
||||
width: 15%;
|
||||
}
|
||||
.login-box{
|
||||
padding: 0% 30%;
|
||||
}
|
||||
|
||||
.login-btn{
|
||||
margin: 10% 2%;
|
||||
text-align: center;
|
||||
}
|
77
src/login-page/Login.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
import React, { Component } from "react";
|
||||
import Logo from "../images/logo1.png";
|
||||
import "./Login.css";
|
||||
import { Link } from "react-router-dom";
|
||||
// import { useTranslation } from "react-i18next";
|
||||
import { withTranslation } from "react-i18next";
|
||||
class Login extends Component {
|
||||
state = {
|
||||
Account: {
|
||||
firstName: "Kevon",
|
||||
lastName: "Green",
|
||||
email: "kevon.green@kcribs.com",
|
||||
password: "Kcribs123",
|
||||
},
|
||||
};
|
||||
|
||||
handleLogin = (e) => {
|
||||
console.log(e);
|
||||
};
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
return (
|
||||
<div className="login-page">
|
||||
<form action="" className="signin-Form" onClick={this.handleLogin}>
|
||||
<img className="app-logo" src={Logo} alt="app-logo" />
|
||||
<h1 className="form-title">{t("Login_header")} </h1>
|
||||
<p>{t("Login_message")}</p>
|
||||
<hr className="hr" />
|
||||
<div className="login-box">
|
||||
<div class="form-group">
|
||||
<label for="email">{t("Login_email")}</label>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="login-email"
|
||||
// value={email}
|
||||
aria-describedby="emailHelp"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">{t("Login_password")}</label>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="login-password"
|
||||
// value={password}
|
||||
placeholder="Enter your password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="form-check-input"
|
||||
id="exampleCheck1"
|
||||
/>
|
||||
<label class="form-check-label" for="exampleCheck1">
|
||||
{t("Login_remember_me")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="login-btn">
|
||||
<Link to="/account">
|
||||
<button type="submit" class="btn btn-lg btn-primary">
|
||||
{t("Login_submit_button")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withTranslation()(Login);
|
37
src/login-page/account/Account.css
Normal file
|
@ -0,0 +1,37 @@
|
|||
.account-info{
|
||||
padding: 7%;
|
||||
text-align: center;
|
||||
background-color: #e7dec8;
|
||||
}
|
||||
|
||||
.account-header{
|
||||
/* margin: 0% 2%; */
|
||||
padding: 0% 2%;
|
||||
}
|
||||
|
||||
.account-img{
|
||||
width: 90%;
|
||||
margin: 10% 12%;
|
||||
}
|
||||
|
||||
.update-account{
|
||||
text-align: left;
|
||||
padding: 4% 7%;
|
||||
}
|
||||
|
||||
.info-group{
|
||||
padding: 1%;
|
||||
}
|
||||
.label-text{
|
||||
font-weight: bold;
|
||||
margin: 2%;
|
||||
|
||||
}
|
||||
|
||||
.update-input{
|
||||
padding: 0% 10%;
|
||||
}
|
||||
.update-btn{
|
||||
padding: 4% 2%;
|
||||
text-align: left;
|
||||
}
|
154
src/login-page/account/Account.js
Normal file
|
@ -0,0 +1,154 @@
|
|||
import React, { Component } from "react";
|
||||
import "./Account.css";
|
||||
import Profile from "../../images/profile-picture.png";
|
||||
import { withTranslation } from "react-i18next";
|
||||
// import { useTranslation } from "react-i18next";
|
||||
|
||||
class Account extends Component {
|
||||
state = {
|
||||
Account: {
|
||||
firstName: "Kevon",
|
||||
lastName: "Green",
|
||||
email: "kevon.green@kcribs.com",
|
||||
password: "Kcribs123",
|
||||
},
|
||||
};
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
return (
|
||||
<div className="account-info">
|
||||
{/* // send information to my login component */}
|
||||
<div className="account-header">
|
||||
<h2 className="account-title">{t("Account_header")}</h2>
|
||||
<p className="account-text">{t("Account_message")}</p>
|
||||
</div>
|
||||
|
||||
<div className="row account-box">
|
||||
<div className="col-4">
|
||||
<img src={Profile} alt="profile-img" className="account-img" />
|
||||
</div>
|
||||
<div className="col-8">
|
||||
<form action="" className="update-account">
|
||||
<div class="row form-group info-group">
|
||||
<div className="col-4">
|
||||
<label class="label-text" for="email">
|
||||
{t("Account_first_name")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="col-8 update-input">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="account-fname"
|
||||
placeholder={this.state.Account.firstName}
|
||||
required
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group info-group">
|
||||
<div className="col-4">
|
||||
<label class="label-text" for="email">
|
||||
{t("Account_last_name")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="col-8 update-input">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="account-lname"
|
||||
placeholder={this.state.Account.lastName}
|
||||
required
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group info-group">
|
||||
<div className="col-4">
|
||||
<label class="label-text" for="email">
|
||||
{t("Account_email")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="col-8 update-input">
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="account-email"
|
||||
aria-describedby="emailHelp"
|
||||
placeholder={this.state.Account.email}
|
||||
required
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group info-group">
|
||||
<div className="col-4">
|
||||
<label class="label-text" for="email">
|
||||
{t("Account_phone_number")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="col-8 update-input">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="account-phoneNumber"
|
||||
placeholder={this.state.Account.email}
|
||||
required
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group info-group">
|
||||
<div className="col-4">
|
||||
<label class="label-text" for="email">
|
||||
{t("Account_current_password")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="col-8 update-input">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="account-existPassword"
|
||||
placeholder={"**************"}
|
||||
required
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div class="row form-group info-group">
|
||||
<div className="col-4">
|
||||
<label class="label-text" for="email">
|
||||
{t("Account_new_password")}
|
||||
</label>
|
||||
</div>
|
||||
<div className="col-8 update-input">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="account-newPassword"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="update-btn">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-lg btn-danger"
|
||||
disabled={true}
|
||||
>
|
||||
{t("Account_update_button")}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//links
|
||||
// https://www.pngitem.com/pimgs/m/146-1468479_my-profile-icon-blank-profile-picture-circle-hd.png
|
||||
|
||||
export default withTranslation()(Account);
|
|
@ -0,0 +1,48 @@
|
|||
.colored-section {
|
||||
background-color: #e7dec8;
|
||||
color: #000000;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
#contact .container-fluid {
|
||||
padding-top: 50px;
|
||||
text-align: left;
|
||||
font-family: "Georgia";
|
||||
}
|
||||
|
||||
|
||||
.contactIntro{
|
||||
padding-left: 10%;
|
||||
padding-right: 10%;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.heading-1{
|
||||
padding-left: 36%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 20%;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.formhelper{
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
#dropdown{
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
[data-feedback] {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
[data-feedback].error {
|
||||
color: red;
|
||||
}
|
||||
|
4
src/shared-components/contact-us/config.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
USER: 'a0f17fd29c4ac0',
|
||||
PASS: '671f8cbe2bd5e2'
|
||||
}
|
|
@ -1,9 +1,233 @@
|
|||
import React, { Component } from "react";
|
||||
import "./Contact-us.css";
|
||||
import axios from 'axios'
|
||||
import {
|
||||
FieldFeedback,
|
||||
FieldFeedbacks,
|
||||
FormWithConstraints
|
||||
} from 'react-form-with-constraints';
|
||||
import Alert from 'react-bootstrap/Alert';
|
||||
import { withTranslation } from "react-i18next";
|
||||
|
||||
|
||||
|
||||
class ContactUs extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
firstname: "",
|
||||
lastname: "",
|
||||
email: "",
|
||||
message: "",
|
||||
agent: "",
|
||||
house: "",
|
||||
alertBad: false,
|
||||
alertSucess: false,
|
||||
time: false
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return <div>ContactUs</div>;
|
||||
const { t } = this.props;
|
||||
return (
|
||||
<div className="contact-us">
|
||||
<Alert variant="danger" style={{ display: this.state.alertBad ? "block" : "none" }} onClose={() => this.setState({ alertBad: false })} dismissible>
|
||||
<Alert.Heading>{t("Danger1")}</Alert.Heading>
|
||||
<p>
|
||||
{t("Danger2")}
|
||||
</p>
|
||||
</Alert>
|
||||
<Alert variant="success" style={{ display: this.state.alertSucess ? "block" : "none" }} onClose={() => this.setState({ alertSucess: false })} dismissible>
|
||||
<Alert.Heading>{t("Success1")}</Alert.Heading>
|
||||
<p>
|
||||
{t("Success2")}
|
||||
</p>
|
||||
</Alert>
|
||||
<div className="container">
|
||||
<section class="colored-section" id="contact">
|
||||
<div className="container-fluid">
|
||||
<div className="contactIntro">
|
||||
<h2 className="heading-1">{t("Contact-Title")}</h2>
|
||||
<FormWithConstraints ref={form => this.form = form}
|
||||
id="contact-form"
|
||||
onSubmit={this.handleSubmit.bind(this)}
|
||||
method="POST"
|
||||
noValidate
|
||||
>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-6">
|
||||
<select className="form-group" name="agent" id="dropdown" required onChange={this.onAgentChange.bind(this)} value={this.state.agent}>
|
||||
<option value="">{t("Contact-Agent")}</option>
|
||||
<option value="Michael">Michael</option>
|
||||
<option value="Jin">Jin </option>
|
||||
<option value="Anita">Anita</option>
|
||||
<option value="Alex">Alex</option>
|
||||
<option value="Xuan">Xuan</option>
|
||||
<option value="Walter">Walter</option>
|
||||
<option value="No preference">{t("No-Pref")}</option>
|
||||
</select>
|
||||
<FieldFeedbacks for="agent">
|
||||
<FieldFeedback when="*">
|
||||
{t("Contact-Error1")}
|
||||
</FieldFeedback>
|
||||
</FieldFeedbacks>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<select className="form-group" name="house" id="dropdown" required onChange={this.onHouseChange.bind(this)} value={this.state.house}>
|
||||
<option value="">{t("Contact-House")}</option>
|
||||
<option value="100 Charlie Rogers">100 Charlie Rogers</option>
|
||||
<option value="1490 Youville Drive">1490 Youville Drive </option>
|
||||
<option value="8720 Russell Road">8720 Russell Road</option>
|
||||
<option value="2785 8th Line Road">2785 8th Line Road</option>
|
||||
<option value="No preference">{t("No-Pref")}</option>
|
||||
</select>
|
||||
<FieldFeedbacks for="agent">
|
||||
<FieldFeedback when="*">
|
||||
{t("Contact-Error1")}
|
||||
</FieldFeedback>
|
||||
</FieldFeedbacks>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="formhelper row">
|
||||
<div className="col-6">
|
||||
<input name="firstname"
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder={t("Contact-First")}
|
||||
value={this.state.firstname}
|
||||
required onChange={this.onFirstNameChange.bind(this)}
|
||||
/>
|
||||
<FieldFeedbacks for="agent">
|
||||
<FieldFeedback when="*">
|
||||
{t("Contact-Error2")}
|
||||
</FieldFeedback>
|
||||
</FieldFeedbacks>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<input name="lastname"
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder={t("Contact-Last")}
|
||||
value={this.state.lastname}
|
||||
required onChange={this.onLastNameChange.bind(this)}
|
||||
/>
|
||||
<FieldFeedbacks for="agent">
|
||||
<FieldFeedback when="*">
|
||||
{t("Contact-Error2")}
|
||||
</FieldFeedback>
|
||||
</FieldFeedbacks>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<input name="email"
|
||||
type="email"
|
||||
className="form-control"
|
||||
placeholder={t("Contact-Mail")}
|
||||
aria-describedby="emailHelp"
|
||||
value={this.state.email}
|
||||
required onChange={this.onEmailChange.bind(this)}
|
||||
/>
|
||||
<FieldFeedbacks for="email">
|
||||
<FieldFeedback when={value => value.length === 0}>{t("Contact-Error2")}</FieldFeedback>
|
||||
<FieldFeedback when={value => !/\S+@\S+/.test(value)}>{t("Contact-Error3")}</FieldFeedback>
|
||||
</FieldFeedbacks>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<textarea name="message"
|
||||
className="form-control"
|
||||
placeholder={t("Contact-Message")}
|
||||
rows="5"
|
||||
value={this.state.message}
|
||||
required onChange={this.onMessageChange.bind(this)}
|
||||
/>
|
||||
<FieldFeedbacks for="agent">
|
||||
<FieldFeedback when="*">
|
||||
{t("Contact-Error1")}
|
||||
</FieldFeedback>
|
||||
</FieldFeedbacks>
|
||||
</div>
|
||||
<div className="buttonhelper">
|
||||
<button type="submit" className="button-1">
|
||||
{t("Contact-Submit")}
|
||||
</button>
|
||||
</div>
|
||||
</FormWithConstraints>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
onAgentChange(event) {
|
||||
this.setState({ agent: event.target.value });
|
||||
}
|
||||
|
||||
onHouseChange(event) {
|
||||
this.setState({ house: event.target.value });
|
||||
}
|
||||
|
||||
onFirstNameChange(event) {
|
||||
this.setState({ firstname: event.target.value });
|
||||
}
|
||||
|
||||
onLastNameChange(event) {
|
||||
this.setState({ lastname: event.target.value });
|
||||
}
|
||||
|
||||
onEmailChange(event) {
|
||||
this.setState({ email: event.target.value });
|
||||
}
|
||||
|
||||
onMessageChange(event) {
|
||||
this.setState({ message: event.target.value });
|
||||
}
|
||||
|
||||
handleChange = e => {
|
||||
this.form.validateFields(e.target);
|
||||
}
|
||||
|
||||
handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.form.validateFields();
|
||||
|
||||
if (!this.form.isValid()) {
|
||||
this.alertBad();
|
||||
return;
|
||||
} else {
|
||||
this.alertSuccess();
|
||||
axios({
|
||||
method: "POST",
|
||||
url: "http://localhost:3002/send",
|
||||
data: this.state
|
||||
}).then((response) => {
|
||||
if (response.data.status === 'success') {
|
||||
this.resetForm();
|
||||
} else if (response.data.status === 'fail') {
|
||||
return;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
alertSuccess() {
|
||||
this.setState({ alertBad: false, alertSucess: true })
|
||||
}
|
||||
|
||||
alertBad() {
|
||||
this.setState({ alertSucess: false, alertBad: true })
|
||||
}
|
||||
|
||||
resetForm() {
|
||||
this.setState({ firstname: '', lastname: '', email: '', message: '', agent: '', house: '' })
|
||||
}
|
||||
}
|
||||
|
||||
export default ContactUs;
|
||||
|
||||
export default withTranslation()(ContactUs);
|
||||
|
|
|
@ -1 +1,60 @@
|
|||
export { default } from "./Contact-us";
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
var nodemailer = require('nodemailer');
|
||||
var cors = require('cors');
|
||||
const creds = require('./config');
|
||||
|
||||
var transport = {
|
||||
host: 'smtp.mailtrap.io', // Don’t forget to replace with the SMTP host of your provider
|
||||
port: 2525,
|
||||
auth: {
|
||||
user: creds.USER,
|
||||
pass: creds.PASS
|
||||
}
|
||||
}
|
||||
|
||||
var transporter = nodemailer.createTransport(transport)
|
||||
|
||||
transporter.verify((error, success) => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
} else {
|
||||
console.log('Server is ready to take messages');
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/send', (req, res, next) => {
|
||||
var firstname = req.body.firstname
|
||||
var lastname = req.body.lastname
|
||||
var email = req.body.email
|
||||
var agent = req.body.agent
|
||||
var house = req.body.house
|
||||
var message = req.body.message
|
||||
var content = `First Name: ${firstname} \n Last Name: ${lastname} \n E-mail: ${email} \n Agent: ${agent} \n House: ${house} \n Message: ${message} `
|
||||
|
||||
var mail = {
|
||||
from: email,
|
||||
to: 'kenes@cribs.com', // Change to email address that you want to receive messages on
|
||||
subject: 'New Message from Contact Form',
|
||||
text: content
|
||||
}
|
||||
|
||||
transporter.sendMail(mail, (err, data) => {
|
||||
if (err) {
|
||||
res.json({
|
||||
status: 'fail'
|
||||
})
|
||||
} else {
|
||||
res.json({
|
||||
status: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const app = express()
|
||||
app.use(cors())
|
||||
app.use(express.json())
|
||||
app.use('/', router)
|
||||
app.listen(3002)
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import React from "react";
|
||||
import "./Footer.css";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Footer = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<footer>
|
||||
<section id="footer">
|
||||
|
@ -9,7 +12,7 @@ const Footer = () => {
|
|||
<i class="fab fa-facebook social-icon"></i>
|
||||
<i class="fab fa-instagram social-icon"></i>
|
||||
<i class="fas fa-envelope social-icon"></i>
|
||||
<p class="">© Copyright SEG3125 - Group 3</p>
|
||||
<p class="">© {t("Footer_message")}</p>
|
||||
</div>
|
||||
</section>
|
||||
</footer>
|
||||
|
|
|
@ -3,14 +3,16 @@ import { Link, withRouter } from "react-router-dom";
|
|||
import "./Navbar.css";
|
||||
import logo from "./logo2.png";
|
||||
/* eslint-disable jsx-a11y/anchor-is-valid */
|
||||
import { useTranslation } from "react-i18next";
|
||||
const Navbar = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
/* Nav Bar */
|
||||
<div className="Navbar">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark">
|
||||
<img src={logo} alt="" width="40" height="40"></img>
|
||||
<a href="/" class="navbar-brand">
|
||||
Kene's Cribs
|
||||
{t("Nav_brand")}
|
||||
</a>
|
||||
<button
|
||||
className="navbar-toggler"
|
||||
|
@ -27,29 +29,36 @@ const Navbar = () => {
|
|||
<ul className="navbar-nav ml-auto">
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" exact to="/">
|
||||
Home
|
||||
{t("Nav_Home")}
|
||||
</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/listings">
|
||||
Listings
|
||||
{t("Nav_Listings")}
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/agents">
|
||||
Agents
|
||||
{t("Nav_Agents")}
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/">
|
||||
Contact Us
|
||||
<Link className="nav-link" to="/contact-us">
|
||||
{t("Nav_Contact_Us")}
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/">
|
||||
Login
|
||||
<Link className="nav-link" to="/listing-page">
|
||||
{t("Nav_listing_page")}
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<li className="nav-item">
|
||||
<Link className="nav-link" to="/login">
|
||||
{t("Nav_Login")}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
|
|