1// This val calculates driving/transit time from given origins to the nearest grocery store, gym, FiDi, Roblox HQ, and Samsara in San Francisco.
2// It uses data from SF_Grocery and SF_Gyms blobs, and the Google Maps Directions API for travel times.
3// It also looks up the neighborhood based on the ZIP code using the SF_Neighborhood_ZIP blob.
4// Results are saved and displayed for each new address added, with options to delete individual results.
307 }
308
309 const apiKey = Deno.env.get("GOOGLE_MAPS_API_KEY");
310 if (!apiKey) {
311 console.error("API key is missing");
312 return new Response(JSON.stringify({ error: "API key is not configured" }), {
313 headers: { "Content-Type": "application/json" },
314 });
325
326 console.log("Finding nearest grocery");
327 const nearestGrocery = await findNearest(origin, groceries, apiKey);
328 console.log("Nearest grocery:", nearestGrocery);
329
330 console.log("Finding nearest gym");
331 const nearestGym = await findNearest(origin, gyms, apiKey);
332 console.log("Nearest gym:", nearestGym);
333
334 console.log("Calculating driving time to FiDi");
335 const fidiDestination = "548 Market St, San Francisco, CA 94104";
336 const fidiDrivingTime = await getDrivingTime(origin, fidiDestination, apiKey);
337 console.log("FiDi driving time:", fidiDrivingTime);
338
339 console.log("Calculating driving time to Roblox");
340 const robloxDestination = "910 Park Pl Ste 300, San Mateo, CA 94403";
341 const robloxDrivingTime = await getDrivingTime(origin, robloxDestination, apiKey, "09:00:00", "Tuesday");
342 console.log("Roblox driving time:", robloxDrivingTime);
343
344 console.log("Calculating transit time to Samsara");
345 const samsaraDestination = "1 De Haro St, San Francisco, CA 94103";
346 const samsaraTransitTime = await getTransitTime(origin, samsaraDestination, apiKey);
347 console.log("Samsara transit time:", samsaraTransitTime);
348
349 console.log("Extracting ZIP code and looking up neighborhood");
350 const zipCode = await getZipCode(origin, apiKey);
351 const neighborhoodZipMap = await blob.getJSON("SF_Neighborhood_ZIP");
352 const neighborhood = neighborhoodZipMap[zipCode] || "Unknown";
397}
398
399async function findNearest(origin: string, locations: any[], apiKey: string): Promise<any> {
400 console.log(`Finding nearest location among ${locations.length} options`);
401 const batchSize = 25; // Google Maps API typically allows up to 25 destinations per request
402 let nearestLocation = null;
403 let shortestTime = Infinity;
406 const batch = locations.slice(i, i + batchSize);
407 const destinations = batch.map(location => `${location.gps.lat},${location.gps.lng}`).join('|');
408 const distanceMatrixUrl = `https://maps.googleapis.com/maps/api/distancematrix/json?origins=${encodeURIComponent(origin)}&destinations=${encodeURIComponent(destinations)}&mode=driving&key=${apiKey}`;
409
410 console.log(`Fetching from Distance Matrix API for batch ${i / batchSize + 1}`);
411 const response = await fetch(distanceMatrixUrl);
412 const data = await response.json();
413 console.log("Distance Matrix API response status:", data.status);
414
415 if (data.status !== "OK") {
416 console.error("Distance Matrix API failed:", data);
417 throw new Error(`Distance Matrix API failed. Status: ${data.status}`);
418 }
419
439}
440
441async function getDrivingTime(origin: string, destination: string, apiKey: string, arrivalTime?: string, arrivalDay?: string): Promise<string> {
442 let directionsUrl = `https://maps.googleapis.com/maps/api/directions/json?origin=${encodeURIComponent(origin)}&destination=${encodeURIComponent(destination)}&mode=driving&key=${apiKey}`;
443
444 if (arrivalTime && arrivalDay) {
460}
461
462async function getTransitTime(origin: string, destination: string, apiKey: string): Promise<string> {
463 const directionsUrl = `https://maps.googleapis.com/maps/api/directions/json?origin=${encodeURIComponent(origin)}&destination=${encodeURIComponent(destination)}&mode=transit&key=${apiKey}`;
464
465 const directionsResponse = await fetch(directionsUrl);
475}
476
477async function getZipCode(address: string, apiKey: string): Promise<string> {
478 const geocodeUrl = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${apiKey}`;
479 const response = await fetch(geocodeUrl);
480 const data = await response.json();