merge with the master branch

This commit is contained in:
soyed 2021-04-05 18:23:55 -04:00
commit 4b2a08a36f
16 changed files with 768 additions and 20618 deletions

View file

@ -1,8 +1,10 @@
# SEG3125-LAB8 # 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 # Authors
- Batuhan Basoglu, 300001274 - ArcticHawk1 - Batuhan Basoglu, 300001274 - ArcticHawk1

20791
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,14 +6,27 @@
"@testing-library/jest-dom": "^5.11.10", "@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.5", "@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.8.3", "@testing-library/user-event": "^12.8.3",
"axios": "^0.21.1",
"bootstrap": "^4.6.0", "bootstrap": "^4.6.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"joi-browser": "^13.4.0",
"nodemailer": "^6.5.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-alert": "^7.0.2",
"react-alert-template-basic": "^1.0.0",
"react-bootstrap": "^1.5.2", "react-bootstrap": "^1.5.2",
"react-bootstrap-carousel": "^4.1.1", "react-bootstrap-carousel": "^4.1.1",
"react-dom": "^17.0.2", "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-google-maps": "^9.4.5",
"react-hook-form": "^7.0.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"react-select": "^4.3.0",
"reactstrap": "^8.9.0",
"spectre.css": "^0.5.9", "spectre.css": "^0.5.9",
"web-vitals": "^1.1.1" "web-vitals": "^1.1.1"
}, },
@ -43,5 +56,18 @@
}, },
"devDependencies": { "devDependencies": {
"create-react-component-folder": "^0.3.7" "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": ""
} }

View file

@ -6,9 +6,10 @@ import HomePage from "./homePage/Homepage";
import ListingsPage from "./listings-page/ListingsPage"; import ListingsPage from "./listings-page/ListingsPage";
import AgentPage from "./agent-page/AgentPage"; import AgentPage from "./agent-page/AgentPage";
import ListingPage from "./listings-page/single-listing/listing-page"; import ListingPage from "./listings-page/single-listing/listing-page";
// import Login from "./login-page/Login"; import Login from "./login-page/Login";
import Account from "./login-page/account/Account"; // import Account from "./login-page/account/Account";
// import ContactUs from "./shared-components/Contact-us/Contact-us"; // import ContactUs from "./shared-components/Contact-us/Contact-us";
import ContactUs from "./shared-components/contact-us/contact-us";
class App extends Component { class App extends Component {
render() { render() {
@ -20,7 +21,8 @@ class App extends Component {
<Route path="/listings" component={ListingsPage}></Route> <Route path="/listings" component={ListingsPage}></Route>
<Route path="/agents" component={AgentPage}></Route> <Route path="/agents" component={AgentPage}></Route>
<Route path="/listing-page" component={ListingPage}></Route> <Route path="/listing-page" component={ListingPage}></Route>
<Route path="/login" component={Account}></Route> <Route path="/login" component={Login}></Route>
<Route path="/contact-us" component={ContactUs}></Route>
</BrowserRouter> </BrowserRouter>
<Footer></Footer> <Footer></Footer>
</div> </div>

View file

@ -4,25 +4,30 @@
white-space: nowrap; white-space: nowrap;
} }
.white-section { .white-section {
background-color: #ffffff; background-color: #ffffff;
padding-top: 10rem;
padding-bottom: 5rem;
padding-left: 18%;
} }
#title .container-fluid { #title .container-fluid {
padding: 4% 34% 6%; padding: 5% 34% 6%;
text-align: left; text-align: left;
font-family: "Georgia"; font-family: "Georgia";
} }
#features .container-fluid { #features .container-fluid {
padding: 2% 48% 2%; padding: 2% 14% 4%;
text-align: left; text-align: left;
font-family: "Georgia"; font-family: "Georgia";
} }
.housesIntro{ .housesIntro{
padding: 4% 5%; width: 1200px;
height: 800px;
} }
.contactIntro{ .contactIntro{
@ -31,23 +36,9 @@
padding-bottom: 80px; padding-bottom: 80px;
} }
.carouselSection {
margin: 2% 8%;
}
.headerImg{ .headerImg{
width: 2000px; width: 1200px;
height: 600px; height: 800px;
}
.heading-1{
padding-left: 40%;
padding-top: 10%;
padding-bottom: 20px;
}
.formhelper{
padding-bottom: 15px;
} }
.button-1 { .button-1 {
@ -67,3 +58,69 @@
padding-left: 45%; padding-left: 45%;
padding-top: 15px; 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%;
}

View file

@ -3,20 +3,23 @@ import "./Homepage.css";
import house1 from "../images/house1.jpg"; import house1 from "../images/house1.jpg";
import house2 from "../images/house2.jpg"; import house2 from "../images/house2.jpg";
import house3 from "../images/house3.jpg"; import house3 from "../images/house3.jpg";
import house4 from "../images/house4.jpg";
import Carousel from "react-bootstrap/Carousel"; import Carousel from "react-bootstrap/Carousel";
import Button from "react-bootstrap/Button";
class Homepage extends Component { class Homepage extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
firstname: "", nextIcon: <span className="next-icon"></span>,
lastname: "", prevIcon: <span className="prev-icon"></span>,
email: "",
message: "",
}; };
} }
render() { render() {
const { nextIcon, prevIcon } = this.state;
return ( return (
<div className="homePage"> <div className="homePage">
<section className="colored-section" id="title"> <section className="colored-section" id="title">
@ -29,98 +32,70 @@ class Homepage extends Component {
</div> </div>
</div> </div>
</section> </section>
<section className="white-section" id="white-section"> <section className="white-section">
<div className="housesIntro"> <div className="housesIntro">
<Carousel> <Carousel nextIcon={nextIcon} prevIcon={prevIcon}>
<Carousel.Item> <Carousel.Item>
<img className="headerImg" src={house1} alt="First House" /> <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" }}>1 Bedroom, 2 Bathroom</h2>
<div className="buttonka">
<Button href="/listings" variant="info">Click for Details</Button>
</div>
</Carousel.Caption>
</Carousel.Item> </Carousel.Item>
<Carousel.Item> <Carousel.Item>
<img className="headerImg" src={house2} alt="Second House" /> <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" }}>1 Bedroom, 2 Bathroom</h2>
<div className="buttonka">
<Button href="/listings" variant="info">Click for Details</Button>
</div>
</Carousel.Caption>
</Carousel.Item> </Carousel.Item>
<Carousel.Item> <Carousel.Item>
<img className="headerImg" src={house3} alt="Third House" /> <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" }}>1 Bedroom, 2 Bathroom</h2>
<div className="buttonka">
<Button href="/listings" variant="info">Click for Details</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" }}>1 Bedroom, 2 Bathroom</h2>
<div className="buttonka">
<Button href="/listings" variant="info">Click for Details</Button>
</div>
</Carousel.Caption>
</Carousel.Item> </Carousel.Item>
</Carousel> </Carousel>
<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" }}>Description </h2>
<p style={{ fontSize: "110%" }}> Welcome to Kene's Cribs. Kene's Cribs is a real estator company which provides the clients with the houses. <br></br>
The houses limited to the clients are only limited to the clients' dreams. In order to further navigate the<br></br>
website, use the navigation bar to switch between pages. Listings page is for browsing houses, Agents page<br></br>
is for browsing the estators, the Contact Us page is for the contacting us and the login page is for our<br></br>
members who want to benefit from our deals. Above are some houses which can interest you. Feel free to<br></br>
click the buttons above to explore the houses you want. </p>
</div>
</div>
</div> </div>
</section> </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)}
/>
</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> </div>
</section> </section>
</div> </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 Homepage;

1
src/homePage/index.js Normal file
View file

@ -0,0 +1 @@
export { default } from "./homePage";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 288 KiB

BIN
src/images/house4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View file

@ -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: 38%;
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;
}

View file

@ -0,0 +1,4 @@
module.exports = {
USER: 'a0f17fd29c4ac0',
PASS: '671f8cbe2bd5e2'
}

View file

@ -1,9 +1,220 @@
import React, { Component } from "react"; 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';
class ContactUs extends Component { class ContactUs extends Component {
constructor(props) {
super(props);
this.state = {
firstname: "",
lastname: "",
email: "",
message: "",
agent: "",
house: "",
alertBad: false,
alertSucess: false,
time: false
};
}
render() { render() {
return <div>ContactUs</div>; return (
<div className="contact-us">
<Alert variant="danger" style={{ display: this.state.alertBad ? "block" : "none" }} onClose={() => this.setState({ alertBad: false })} dismissible>
<Alert.Heading>Message could not send.</Alert.Heading>
<p>
There are some errors in your contact form.
</p>
</Alert>
<Alert variant="success" style={{ display: this.state.alertSucess ? "block" : "none" }} onClose={() => this.setState({ alertSucess: false })} dismissible>
<Alert.Heading>The message is successfully sent.</Alert.Heading>
<p>
You contact form will be delivered to our support team.
</p>
</Alert>
<div className="container">
<section class="colored-section" id="contact">
<div className="container-fluid">
<div className="contactIntro">
<h2 className="heading-1">Contact Us</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="">Select an 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">No preference</option>
</select>
<FieldFeedbacks for="agent">
<FieldFeedback when="*" />
</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="">Select a 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">No preference</option>
</select>
<FieldFeedbacks for="house">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
</div>
<div className="formhelper row">
<div className="col-6">
<input name="firstname"
type="text"
className="form-control"
placeholder="First Name"
value={this.state.firstname}
required onChange={this.onFirstNameChange.bind(this)}
/>
<FieldFeedbacks for="firstname">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
<div className="col-6">
<input name="lastname"
type="text"
className="form-control"
placeholder="Last Name"
value={this.state.lastname}
required onChange={this.onLastNameChange.bind(this)}
/>
<FieldFeedbacks for="lastname">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
</div>
<div className="form-group">
<input name="email"
type="email"
className="form-control"
placeholder="Email Address"
aria-describedby="emailHelp"
value={this.state.email}
required onChange={this.onEmailChange.bind(this)}
/>
<FieldFeedbacks for="email">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
<div className="form-group">
<textarea name="message"
className="form-control"
placeholder="Message"
rows="5"
value={this.state.message}
required onChange={this.onMessageChange.bind(this)}
/>
<FieldFeedbacks for="message">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
<div className="buttonhelper">
<button type="submit" className="button-1">
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 ContactUs;

View file

@ -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', // Dont 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)

View file

@ -43,7 +43,7 @@ const Navbar = () => {
</li> </li>
<li className="nav-item"> <li className="nav-item">
<Link className="nav-link" to="/"> <Link className="nav-link" to="/contact-us">
Contact Us Contact Us
</Link> </Link>
</li> </li>