Tech stack - node.js(express) server, react front-end
components folder structure
|__src
| |__components
| |__App
| | |__App.js
| | |__App.css
| |__Business
| | |__Business.js
| | |__Business.css
| |__BusinessList
| | |__BusinessList.js
| | |__BusinessList.css
| |__SearchBar
| |__img
| |__SearchBar.js
| |__SearchBar.css
|__util
|__yelp.js
What i want to happen
When a user enters input into "Search Businesses" and enters input into "Where?" and clicks "Let's go button" it should retrieve the category typed in, EX: "Pizza" and location typed in, EX: "Denver"
In other words, a user should be able to "Search Businesses" and enter a location "Where" and filter the results
How this is working
With a click of the Let's Go button, it calls the searchYelp function which is being imported from yelp.js into App.js inside of yelp.js searchYelp function it fetches the endpoint '/api/hello' from the express server that's calling the API.
What's happening currently
So currently no filtering is happening and when you click the "Let's Go" button it returns a list of random businesses
I have the filtering code setup I just don't know how to implement it to get it working...
Heres the code
SearchBar.js
import React from 'react';
import './SearchBar.css';
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
term: '',
location: '',
sortBy: 'best_match'
}
this.handleTermChange = this.handleTermChange.bind(this)
this.handleLocationChange = this.handleLocationChange.bind(this)
this.handleSearch = this.handleSearch.bind(this)
this.sortByOptions = {
'Best Match': 'best_match',
'Highest Rated': 'rating',
'Most Reviewed': 'review_count'
};
}
getSortByClass(sortByOption) {
if (this.state.sortBy === sortByOption) {
return 'active'
}
return ''
}
handleSortByChange(sortByOption) {
this.setState({
sortBy: sortByOption
})
}
handleTermChange(event) {
this.setState({
term: event.target.value
})
}
handleLocationChange(event) {
this.setState({
location: event.target.value
})
}
handleSearch(event) {
this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy)
event.preventDefault()
}
renderSortByOptions() {
return Object.keys(this.sortByOptions).map(sortByOption => {
let sortByOptionValue = this.sortByOptions[sortByOption]
return <li onClick={this.handleSortByChange.bind(this, sortByOptionValue)} className={this.getSortByClass(sortByOptionValue)} key={sortByOptionValue}>{sortByOption}</li>;
})
}
render() {
return (
<div className="SearchBar">
{this.searchYelp}
<div className="SearchBar-sort-options">
<ul>
{this.renderSortByOptions()}
</ul>
</div>
<div className="SearchBar-fields">
<input onChange={this.handleTermChange} placeholder="Search Businesses" />
<input onChange={this.handleLocationChange} placeholder="Where?" />
<button className="SearchBar-submit" onClick={this.handleSearch}>Let's Go</button>
</div>
</div>
)
}
};
export default SearchBar;
App.js
import React from 'react';
import BusinessList from '../BusinessList/BusinessList';
import SearchBar from '../SearchBar/SearchBar';
import Yelp from '../../util/yelp';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
businesses: [],
};
this.searchYelp = this.searchYelp.bind(this);
}
searchYelp(term) {
Yelp.searchYelp(term).then((businesses) => {
this.setState({ businesses: businesses })
})
}
render() {
return (
<div className="App">
<SearchBar searchYelp={this.searchYelp} />
<BusinessList businesses={this.state.businesses} />
</div>
)
}
}
export default App;
Yelp.js
const { default: SearchBar } = require("../components/SearchBar/SearchBar");
const Yelp = {
searchYelp(term) {
return fetch('/api/hello/:term')
.then((response) => {
console.log(response)
return response.json()
}).then((jsonResponse) => {
console.log(jsonResponse)
if (jsonResponse.businesses) {
return jsonResponse.businesses.map((business) => {
return {
id: business.id,
imageSrc: business.image_url,
name: business.name,
address: business.location.address1,
city: business.location.city,
state: business.location.state,
zipCode: business.location.zip_code,
category: business.categories.title,
rating: business.rating,
reviewCount: business.review_count,
}
})
}
})
}
}
export default Yelp
And the server
I was trying to filter the term only to test but was unsuccessful, If I could get the term and location working I would be fine with that I think, and leave out sortBy...
Server.js
const express = require('express');
const axios = require('axios');
require('dotenv').config();
const cors = require('cors');
const bodyParser = require('body-parser');
const app = express();
app.use(cors());
const port = process.env.PORT || 5000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const apiKey = process.env.APIKEY
app.get('/api/hello/:term', (req, res) => {
const term = req.params.term
const config = {
method: 'get',
url: 'https://api.yelp.com/v3/businesses/search?term=${term}&location=${location}',
headers: {
'Authorization': `Bearer ${apiKey}`
}
};
axios(config)
.then(function (response) {
// res.send(JSON.stringify(response.data, null, 2));
// res.send(term)
return JSON.stringify(response.data, null, 2)
})
.then(function (jsonResponse) {
res.send(jsonResponse)
})
.catch(function (error) {
console.log(error);
});
});
app.listen(port, () => console.log(`Listening on port ${port}`));
Heres a screenshot of the web app
CodePudding user response:
if you want to use the built-in capability of the yelp location
filter, you better express it in your express app (pun intended!):
app.get('/api/hello/', (req, res) => {
// use query instead of params,
// and destruct location as well
const {term, location} = req.query
const config = {
method: 'get',
url: 'https://api.yelp.com/v3/businesses/search?term=${term}&location=${location}',
headers: {
'Authorization': `Bearer ${apiKey}`
}
};
}
... and pass query parameters in the front end:
const Yelp = {
// take care to update any existing calls
// to this function with the location parameter
searchYelp(term, location) {
return fetch(`/api/hello?term=${term}&location=${location}`)
// etc. etc. ...
if you just want to filter it in the front end (not recommended), and the location input will always hold a city name (and you can enforce it) - you're nearly there, all that's left to do is to declare the new function arguments, and filter the result:
function searchYelp(term, location, sortBy) {
// ...
this.setState({ businesses: businesses.filter(business => business.city === location) })
// ...
}
if you still don't want to use yelp API's location
, and want a more fuzzy search (i.e. to be able to feed a general term, like "brooklyn", and output exact info like city, state, zip code etc.), you would have to implement some sort of autocomplete mechanism on the location input, which will involve further calls to some backend service.