Skip to content
This repository has been archived by the owner on Feb 9, 2024. It is now read-only.

London-10 | Iryna Lypnyk | React | cyf-hotel-react #608

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[Demo](https://cyf-irynalypnyk-hotel-react.netlify.app/)


A hotel booking application in React. Homework for the [CodeYourFuture React module](https://codeyourfuture.github.io/syllabus-master/react/)

![Bookings Search page](Bookings.png)
Expand Down
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"moment": "^2.29.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1"
Expand Down
Binary file added public/images/glasgow.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/london.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/manchester.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Diphylleia&family=Moirai+One&family=Montserrat:wght@300;400&display=swap" rel="stylesheet">

<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<!--
Expand Down
104 changes: 89 additions & 15 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,15 +1,52 @@
:root {
--blue: #007bff;
--greyBg: #f8f9fa;
}

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

html {
font-size: 16px;
line-height: 1.2;
font-family: 'Montserrat', sans-serif;
}

html, body, #root {
width: 100%;
height: 100%;
}
ul, li {
list-style-position: inside;
}

#root {
width: 100%;
height: 100%;
}

.App {
text-align: left;
}

.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
//animation: App-logo-spin infinite 20s linear;
height: 40px;
margin-right: 20px;

}

.App-logo-text{
font-family: 'Moirai One', cursive;
}

.App-header {
background-color: #222;
height: 50px;
display: flex;
/*background-color: #736F72;*/
height: auto;
padding: 20px;
color: white;
text-align: left;
Expand All @@ -23,35 +60,72 @@
}

.App-content {
padding-top: 20px;
padding-top: 40px;
font-size: large;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.search {
padding: 5px 0 20px 0;
}

tr {
color: #5b5757;
cursor: pointer;
}

tr.selected {
color: var(--blue);
background-color: var(--greyBg);
}

.card-deck-grid{
display: grid!important;
grid-template-rows: auto;
grid-template-columns: 1fr;
row-gap: 24px;
}

.card-body {
flex: 1 1 auto;
}

.card-footer{
border-top: none;
background-color: initial;
padding-bottom: 25px;
}

.results {
padding-top: 15px;
}

.searchResult {
overflow-x: auto;
}

.searchResult .table {
font-size: 14px;
width: 100%;
}

.searchResult .btn{
white-space: nowrap;
}

.orders {
display: flex;
flex-direction: column;
row-gap: 10px;
}

.footer {
padding-top: 20px;
padding-bottom: 20px;
text-align: center;
}

.card {
width: 18rem;
@media (min-width: 900px){
.card-deck-grid{
grid-template-columns: repeat(3, 1fr);
}
}
20 changes: 17 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import React from "react";
import "./App.css";

import Bookings from "./Bookings";
import "./App.css";
import Footer from "./Footer";
import Heading from "./Heading";
import Restaurant from "./Restaurant";
import TouristInfoCards from "./TouristInfoCards";

const data = ["123 Fake Street, London, E1 4UD", "[email protected]", "0123 456789"];

const App = () => {

return (
<div className="App">
<header className="App-header">CYF Hotel</header>
<Bookings />
<Heading />
<div className="App-content">
<div className="container">
<TouristInfoCards />
<Bookings />
<Restaurant />
</div>
</div>
<Footer data={data} />
</div>
);
};
Expand Down
53 changes: 48 additions & 5 deletions src/Bookings.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,61 @@
import React from "react";
import React, { useEffect, useState } from "react";
import Search from "./Search.js";
// import SearchResults from "./SearchResults.js";
// import FakeBookings from "./data/fakeBookings.json";
import SearchResults from "./SearchResults.js";
//import FakeBookings from "./data/fakeBookings.json";

const Bookings = () => {
const [bookings, setBookings] = useState([]);
const [filteredBookings, setFilteredBookings] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(false);

useEffect(() => {
setIsLoading(true);
fetch("https://cyf-react.glitch.me")
.then(res => {
if(res.status >= 400) {
throw new Error("Server responds with error!");
} else {
return res.json()
}})
.then(data => {
setBookings(data);
setIsLoading(false);
},
err => {
setError(err)
setIsLoading(false);
});
}, []);

useEffect(()=> {
setFilteredBookings(bookings)
}, [bookings])


const search = searchVal => {
console.info("TO DO!", searchVal);
if(searchVal) {
const filteredBookings = bookings.filter(booking => {
const {firstName, surname} = booking;
const preparedSearchVal = searchVal.toLowerCase();
const preparedFirstName = firstName.toLowerCase();
const preparedSurname = surname.toLowerCase();
return preparedFirstName.includes(preparedSearchVal) || preparedSurname.includes(preparedSearchVal)
});
setFilteredBookings(filteredBookings);
} else {
setFilteredBookings(bookings);
Comment on lines +37 to +47
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done, everything that follows has nothing to do with functionality as they are the exact same but want to talk about coding style. Do take these with a pinch of salt as styling varies from developer to developer, but worth sharing as it's always nice to know someone else's style.

I, personally, find that having too many variables can sometimes make the code harder to follow. So for example there are quite a few temporary variables within your filter that are reassigned. Sometimes that makes it easier to read but sometimes it can make it harder and is a balancing act to be aware of.

The second comment is that as your else branch is the case where you do nothing to the original bookings, it can be done in a different way to having two different calls to the setter.

const search = (searchVal) => {
  let searchQuery = searchVal.toLowerCase();
  let bookingResults = bookings;
  
  if (searchQuery) {
    bookingResults = bookings.filter({ firstName, surname } => {
      return firstName.toLowerCase().includes(searchQuery) || surname.toLowerCase().includes(searchQuery);
    });
  }
  
  setFilteredBookings(bookingResults)
}

}
};


return (
<div className="App-content">
<div className="container">
<Search search={search} />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you think how you'd modify this code so that the search function lives in the search component?

Some questions that might help you think about a way you could are:

  1. Is the bookings state needed anywhere else other than the search?
  2. Which setState functions would you need to pass down into the search component

{/* <SearchResults results={FakeBookings} /> */}
{isLoading && <div>Loading...</div>}
{!isLoading && error && <div>{error.message} </div>}
{!isLoading && bookings && <SearchResults results={filteredBookings} />}
</div>
</div>
);
Expand Down
30 changes: 30 additions & 0 deletions src/CustomerProfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useEffect, useState } from "react";

function CustomerProfile({id}) {
const [profile, setProfile] = useState(id)

useEffect(()=>{
fetch(`https://cyf-react.glitch.me/customers/${id}`)
.then(res=>res.json())
.then(data=>setProfile(data));
},[id])

return (
<>
{profile ? (
<div className="App-content">
<h4>Customer profile</h4>
<ul>
<li>Customer ID: {profile.id}</li>
<li>VIP: {profile.vip ? "Yes" : "No"}</li>
<li>Email: {profile.email}</li>
<li>Tel: {profile.phoneNumber}</li>
</ul>
</div>
) : null}
</>

);
}

export default CustomerProfile;
13 changes: 13 additions & 0 deletions src/Footer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";

const Footer = ({data}) => {
return (
<footer className="footer bg-light">
<ul>
{data.map(item => (<ul key={item}>{item}</ul>))}
</ul>
</footer>
);
};

export default Footer;
12 changes: 12 additions & 0 deletions src/Heading.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";

const Heading = () => {
return (
<header className="App-header bg-dark">
<img src="/images/logo.png" alt="logo" className="App-logo"/>
<h1 className="App-logo-text">CYF Hotel</h1>
</header>
);
};

export default Heading;
16 changes: 16 additions & 0 deletions src/InfoCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';

function InfoCard({img, title, descr, link}) {
return (
<div className="card">
<img src={img} className="card-img-top" />
<div className="card-body">
<h3 className="card-title">{title}</h3>
<p className="card-text">{descr}</p>
</div>
<div className="card-footer"><a href={link} className="btn btn-outline-primary">More Information</a></div>
</div>
);
}

export default InfoCard;
17 changes: 17 additions & 0 deletions src/Order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { useState } from "react";

function Order({orderType}) {
const [orders, setOrders] = useState(0);

const orderOne = () => {
setOrders(orders + 1);
}

return (
<li>
{orderType}: {orders} <button className="btn btn-primary" onClick={orderOne}>Add</button>
</li>
);
}

export default Order;
Loading