-
Notifications
You must be signed in to change notification settings - Fork 11
Promise homework - Stephanie's solution #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
8a3a84d
b03419e
f1a6297
c5bf23b
47880be
9d5cfff
ba1ad1d
96ff018
ec1033b
8ab90c1
6f4a18a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,4 +13,4 @@ | |
"test": "react-scripts test --env=jsdom", | ||
"eject": "react-scripts eject" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,86 @@ | ||
.App { | ||
text-align: center; | ||
|
||
* { | ||
margin: 0; | ||
padding: 0; | ||
} | ||
|
||
.App-logo { | ||
animation: App-logo-spin infinite 20s linear; | ||
height: 80px; | ||
body { | ||
font-family: sans-serif; | ||
} | ||
|
||
|
||
input[type="text"], input[type="submit"], button { | ||
appearance: none; | ||
padding: 0.6rem 1rem; | ||
font-size: 1rem; | ||
outline: none; | ||
border: 2px solid #ee4e7a; | ||
border-radius: 4px; | ||
margin-right: 0.4rem; | ||
} | ||
|
||
.App-header { | ||
background-color: #222; | ||
height: 150px; | ||
padding: 20px; | ||
color: white; | ||
input[type="submit"], button { | ||
background-color: #ee4e7a; | ||
color: #fff; | ||
cursor: pointer; | ||
} | ||
|
||
.App-title { | ||
font-size: 1.5em; | ||
.error-message { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
min-height: 600px; | ||
font-size: 1.4rem; | ||
color: #444; | ||
} | ||
|
||
.App-intro { | ||
font-size: large; | ||
.search { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
margin: 2rem 0; | ||
} | ||
|
||
@keyframes App-logo-spin { | ||
from { transform: rotate(0deg); } | ||
to { transform: rotate(360deg); } | ||
.list { | ||
max-width: 800px; | ||
margin: 0 auto; | ||
} | ||
|
||
.list ul { | ||
list-style: none; | ||
} | ||
|
||
.list li { | ||
border: 1px solid #eee; | ||
padding: 1rem 1.6rem; | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
color: #444; | ||
} | ||
|
||
.list--title { | ||
flex: 2; | ||
display: flex; | ||
align-items: center; | ||
margin-right: 1rem; | ||
} | ||
|
||
.list li a { | ||
color: #444; | ||
} | ||
|
||
.list li img { | ||
width: 80px; | ||
height: 80px; | ||
margin-right: 1rem; | ||
} | ||
|
||
|
||
.list span { | ||
/*flex: 1;*/ | ||
background-color: #eee; | ||
color: #ee4e7a; | ||
padding: 0.2rem 0.4rem; | ||
border-radius: 4px; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,114 @@ | ||
import React, { Component } from 'react'; | ||
import logo from './logo.svg'; | ||
import './App.css'; | ||
|
||
import { RecipeList } from './components/RecipeList'; | ||
import { SearchBar } from './components/SearchBar'; | ||
|
||
import { APP_ID, APP_KEY } from './config/'; | ||
|
||
const ErrorMessage = ({message, isLoading}) => { | ||
return ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like to write my functions without |
||
<div className="error-message"> | ||
{ | ||
isLoading ? "Loading recipes..." : message | ||
} | ||
</div> | ||
); | ||
}; | ||
|
||
class App extends Component { | ||
constructor(){ | ||
super(); | ||
this.state = { | ||
searchTerm: '', | ||
recipes: { | ||
fetchedList: [], | ||
errorMessage: '' | ||
}, | ||
isLoading: false | ||
} | ||
} | ||
|
||
updateSearchTerm = (e) => { | ||
this.setState({ | ||
searchTerm: e.target.value | ||
}); | ||
} | ||
|
||
onClickSearch = (e) => { | ||
e.preventDefault(); | ||
this.fetchRecipes(this.state.searchTerm); | ||
} | ||
|
||
fetchRecipes = (searchTerm) => { | ||
const BASE_ENDPOINT = `https://api.edamam.com/search?q=${searchTerm}&app_id=${APP_ID}&app_key=${APP_KEY}`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would even consider moving the BASE_ENDPOINT into it's own file. |
||
|
||
this.setState({ | ||
isLoading: true | ||
}); | ||
|
||
fetch(BASE_ENDPOINT) | ||
.then(res => res.json()) | ||
.then(recipes => { | ||
if(recipes.hits.length > 0) { | ||
const data = recipes.hits.map(({recipe}) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice use of map! Remember that passing in your adaption function is good for code reuse. Also, you don't need Object.assign here, but I like that you're making sure your being immutible. You could do:
which returns a new object (without mutations) |
||
return Object.assign({}, { | ||
name: recipe.label, | ||
calories: Math.floor(recipe.calories), | ||
image: recipe.image, | ||
url: recipe.url | ||
}); | ||
}); | ||
this.setState({ | ||
searchTerm: '', | ||
recipes: { | ||
fetchedList: data, | ||
errorMessage: [] | ||
}, | ||
isLoading: false | ||
}); | ||
} | ||
else { | ||
this.setState({ | ||
recipes: { | ||
fetchedList: [], | ||
errorMessage: `Sorry. We cannot find recipes of ${this.state.searchTerm}. Please search for another food item.` | ||
}, | ||
isLoading: false | ||
}); | ||
} | ||
}) | ||
.catch(err => { | ||
this.setState({ | ||
recipes: { | ||
fetchedList: [], | ||
errorMessage: 'Oops...Failed to load recipes. Please let us know what went wrong!' | ||
}, | ||
isLoading: false | ||
}); | ||
}); | ||
}; | ||
|
||
componentDidMount(){ | ||
this.fetchRecipes('cake'); | ||
} | ||
|
||
render() { | ||
return ( | ||
<div className="App"> | ||
<header className="App-header"> | ||
<img src={logo} className="App-logo" alt="logo" /> | ||
<h1 className="App-title">Welcome to React</h1> | ||
</header> | ||
<p className="App-intro"> | ||
To get started, edit <code>src/App.js</code> and save to reload. | ||
</p> | ||
<SearchBar | ||
inputValue={this.state.searchTerm} | ||
updateSearchTerm={this.updateSearchTerm} | ||
onClickSearch={this.onClickSearch} | ||
/> | ||
{ | ||
this.state.recipes.fetchedList.length > 0 ? | ||
<RecipeList recipes={this.state.recipes.fetchedList} /> : | ||
<ErrorMessage | ||
isLoading={this.state.isLoading} | ||
message={this.state.recipes.errorMessage} | ||
/> | ||
} | ||
</div> | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import React from 'react'; | ||
|
||
export const RecipeList = ({recipes}) => { | ||
return( | ||
<ul className="list"> | ||
{ | ||
recipes.map(({name, calories, url, image}, idx) => { | ||
return ( | ||
<li key={idx}> | ||
<div className="list--title"> | ||
<img src={image} /> | ||
<h3><a href={url}>{name}</a></h3> | ||
</div> | ||
<span>{calories} kcals</span> | ||
</li> | ||
) | ||
}) | ||
} | ||
</ul> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import React from 'react'; | ||
|
||
export const SearchBar = ({inputValue, onClickSearch, updateSearchTerm}) => { | ||
return ( | ||
<form className="search" onSubmit={onClickSearch}> | ||
<input | ||
type="text" | ||
value={inputValue} | ||
onChange={updateSearchTerm} | ||
/> | ||
<input type="submit" value="Search"/> | ||
</form> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export const APP_ID = '9f1497b3'; | ||
export const APP_KEY = 'd489d7c7d4bec18f15a54e7467e0e936'; |
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice job, moving keys into a new file