Open chasestarr opened 8 years ago
integrate google maps api with a database to keep track of "flagged" locations.
Take advantage of Yelp search api to grab relevant cafe locations. Add link to review the location, provide rating in app.
github repo: https://github.com/chasestarr/fifty-fifty
Yelp API documentation: https://www.yelp.com/developers/documentation/v2/overview
video overview of yelp API: https://youtu.be/K_Fvx7pKlSE?t=3m44s
notes from the video: search api pull local bus based on location and geospacial gps, city name - aid in getting that api
search api, business api search - high level business - business lookup
ssearch by gps, city or neighborhood
business api - review snippet action links delivery, make reservation
I kind of like the visuals of https://www.mapbox.com/ more than google maps.. will need to research and compare the apis.
Completed basic search functionality.
At this point the app can:
To do:
Ran into an issue that I did not foresee (although I should have).
Once I have a map with markers loaded to the screen, If I click the "host table" button - how will my app know which business was triggered?
I send a geojson object into mapbox to display the markers.. There has to be a way to read from that data.
I want this to work like the picture above. Not sure how farmlogs does it...
"host table" could trigger a page reload.
Edit: this still doesn't solve the "not knowing which marker is selected" problem
OK sort of figured it out, but it feels a bit hacky...
tooltip description variable:
var descript = "Address: " + element.location.address[0] +
"<br>Rating: " + starRating(element.rating) +
"<br><button type='button' class='hostButton' id ='" + element.id + "'>Host table</button>";
This will add the business id from yelp's api as the id of each "host table" button. When the button is clicked, check what the id is then perform db update on that id data.
I ran into a weird bug in my tooltip code:
var descript = "Address: " + element.location.address[0] +
"<br>Rating: " + starRating(element.rating) +
'<br><button onclick="hostTable();" type="button" class="hostButton" id ="' + element.id + '">Host table</button>';
For some reason, onclick never makes it into the rendered html. Below is the output from chrome inspector:
<button type="button" class="hostButton" id="fifty-fifty-coffee-and-tea-san-francisco">Host table</button>
This issue on stackoverflow seems a bit related..
Found out that leaflet does not render links and onclicks within the map. I needed to "bind" the html contents to a custom tooltip layout. Based this format from here.
var map = L.mapbox.map('map', 'mapbox.light').setView({{center|json|raw}}, 12);
var myLayer = L.mapbox.featureLayer().addTo(map);
myLayer.on('layeradd', function(e) {
var marker = e.layer;
var feature = marker.feature;
var content = "<b><a href='"+ feature.properties.url + "' target='_blank' class='businessTitle'>" + feature.properties.title + "<\/a><\/b>" +
"<br>Address: " + feature.properties.address +
"<br>Rating: " + feature.properties.rating +
"<br><button onclick='hostTable();' type='button' class='hostButton' id='" + feature.properties.id + "'>Host table<\/button>";
marker.bindPopup(content, {closeButton: false});
});
myLayer.setGeoJSON({{geojson|json|raw}});
...whew there's not that much information about this effect. :dizzy:
I've been stuck on an issue with returning the result of an async database lookup for a couple of days now.
var searchYelp = function(params, callback){
yelp.search(params, function(e,res){
// console.log(res);
if(e) return console.log(e);
var center = [res.region.center.latitude, res.region.center.longitude];
//Map api response to format readable by mapbox
var businessData = res.businesses.map(function(element){
var coordObj = element.location.coordinate;
var output = readDB(element.id, function(tableStatus){
var obj = {
type: "Feature",
geometry:{
type: "Point",
coordinates: [coordObj.longitude,coordObj.latitude]
},
properties:{
title: element.name,
url: element.url,
address: element.location.address[0],
rating: starRating(element.rating),
host: tableStatus,
id: element.id,
"marker-color": "#fc4353",
"marker-size": "small"
}
};
return obj;
});
console.log(output);
});
//package data to not repeat center obj
var geoObj = {
center: center,
geoJSON: businessData
}
callback(geoObj);
});
};
var readDB = function(id, callback){
MongoClient.connect('mongodb://localhost:27017/fifty-fifty', function(e,db){
var cursor = db.collection("tables").find({_id: id});
cursor.each(function(e,doc){
if(e) throw e;
if(doc == null){
callback(false);
} else {
callback(doc.host);
}
});
});
};
Currently, the program reaches console.log(output) before any value for it has been defined. I've been trying different ways to solve this issue, but I seem to always be coming back to this same problem. some variable has not been defined
this stackoverflow thread could be helpful. Haven't had a chance to read yet.
http://stackoverflow.com/questions/25229739/race-condition-and-common-mistakes
Back after a bit of a break from writing these entires. In the mean time I ask for some help on the project from a friend. He helped me out quite a bit by explaining some best practices when working with mongodb (using the mongoose package) as well as explained how to use js promises.
From what I understand, promises work similarly to callbacks in that they execute the next block in the chain once an action has finished (in my case a db lookup or an async function).
I learned what "callback hell" was! haha - basically my life last week. :astonished: The promise code structure made my code more linear and easier to follow. It turns out that my issue was: i needed to return the geojson object to mapbox, but it was being held up by the db lookup!
We fixed the issue by refactoring the code to populate a new array with each geojson object, and set up a counter on the action. Once the counter reaches the array length, execute my callback and then send the data to the front-end html.
Once this whole ordeal was worked out, I refactored all of my code into ES6. This wasn't too tough; mostly just updating anonymous functions to fat arrow syntax, converting vars to lets, and fixing a couple bugs when in "strict" mode.
The only weird thing was in my "app.listen" call, I could not convert that anonymous function into the new syntax. I looked up the issue and there seem to be some quirks when combining the "this" keyword with the new format. I haven't had a chance to dive into how "this" works yet, but I plan on it soon!
^^^ Going back to the app.listen weirdness. I started reading the "You don't know JS" chapter on "this" and object prototypes. Turns out that the fact arrow actually points the "this" keyword to the lexical scope. It looks like that break's the pattern express is using to get the listen function working.
in true hacker fashion, I wrote some really gross code to get the app to save previous locations. Before this, whenever you would "host" a table, it would reset the map view back to the default location, rather than center the map over your previous location.
let locPrev = "";
if(loc && locPrev == ""){
locPrev = loc;
params = {term: 'coffee', location: loc};
} else if(loc == null && locPrev == ""){
params = {term: 'coffee', location: 'san+francisco'};
} else if(loc && locPrev != ""){
locPrev = loc;
params = {term: 'coffee', location: loc};
} else {
params = {term: 'coffee', location: locPrev};
}
Not very elegant, but it works for now. :dizzy:
All of my planned functionality has been implemented.
Behind the scenes I managed to:
Woo! so I reorganized the code structure for the project. At first the task seemed quite large, but once getting started it turned out to be fairly straightforward.
I did a good amount of research into the node module system and it makes a lot of sense! :sunglasses:
I got the www.letspl.it domain!
When working at a busy cafe, you can flag your table on the site with an open seat at your table.