@@ -1,40 +1,11 @@ |
| 1 | | -// src/App.js - Complete working app in one file for quick testing |
| 1 | +// src/App.js - Complete working app with fixes |
| 2 | 2 | import React, { useState } from 'react'; |
| 3 | 3 | import './App.css'; |
| 4 | | - |
| 5 | | -// Mini roast database for testing |
| 6 | | -const roastDatabase = { |
| 7 | | - 'New York': [ |
| 8 | | - "NYC? Let me guess, you've mentioned you're from New York within 5 minutes of every conversation you've ever had.", |
| 9 | | - "From NYC? Cool, how's that superiority complex and vitamin D deficiency working out?", |
| 10 | | - "New York City: Where everyone walks fast to nowhere important and calls it ambition." |
| 11 | | - ], |
| 12 | | - 'California': [ |
| 13 | | - "California? How's that $8 gas and $15 avocado toast treating you?", |
| 14 | | - "Oh, you're from California? Which wellness trend are you pretending changed your life this week?", |
| 15 | | - "California: Come for the weather, stay because you can't afford to leave." |
| 16 | | - ], |
| 17 | | - 'Texas': [ |
| 18 | | - "Texas? Everything's bigger there, especially the egos and the power grid failures.", |
| 19 | | - "From Texas? Let me guess, you've already mentioned how big your state is three times today.", |
| 20 | | - "Texas: Where 105°F is 'nice weather' and a light dusting of snow shuts down civilization." |
| 21 | | - ], |
| 22 | | - 'Virginia': [ |
| 23 | | - "Virginia? The state that can't decide if it's the South or just South of Maryland.", |
| 24 | | - "From Virginia? Home of 'Virginia is for Lovers' - because you need a slogan when you have no personality.", |
| 25 | | - "Virginia: Where Northern Virginia pretends it's DC and the rest pretends it's still 1865.", |
| 26 | | - "Oh, Virginia? The state whose biggest achievement is being close to somewhere important.", |
| 27 | | - "Virginia: Where everyone works for the government but swears they're a 'small government conservative'." |
| 28 | | - ], |
| 29 | | - 'default': [ |
| 30 | | - "Your location is so irrelevant, even Google Maps just shrugs.", |
| 31 | | - "From there? I'd roast your hometown but it would require me to care about it first.", |
| 32 | | - "Your area is so forgettable, even this roast generator had nothing prepared." |
| 33 | | - ] |
| 34 | | -}; |
| 4 | +import { getRoastsForLocation } from './services/roastService'; |
| 35 | 5 | |
| 36 | 6 | function App() { |
| 37 | 7 | const [location, setLocation] = useState(null); |
| 8 | + const [locationObj, setLocationObj] = useState(null); // Store the structured object separately |
| 38 | 9 | const [currentRoast, setCurrentRoast] = useState(null); |
| 39 | 10 | const [loading, setLoading] = useState(false); |
| 40 | 11 | const [error, setError] = useState(null); |
@@ -50,20 +21,35 @@ function App() { |
| 50 | 21 | const response = await fetch('https://ipapi.co/json/'); |
| 51 | 22 | const data = await response.json(); |
| 52 | 23 | |
| 53 | | - // Build location string from most specific to least specific |
| 24 | + // Build location object from API response |
| 25 | + const locationObj = { |
| 26 | + city: data.city || null, |
| 27 | + state: data.region || null, |
| 28 | + country: data.country_name || null |
| 29 | + }; |
| 30 | + |
| 31 | + // Create display string |
| 54 | 32 | let locationStr = ''; |
| 55 | 33 | if (data.city) { |
| 56 | 34 | locationStr = data.city; |
| 57 | 35 | if (data.region) { |
| 58 | | - locationStr = data.region; // Use state/region as primary identifier |
| 36 | + locationStr += `, ${data.region}`; |
| 37 | + } |
| 38 | + if (data.country_name) { |
| 39 | + locationStr += `, ${data.country_name}`; |
| 59 | 40 | } |
| 60 | 41 | } else if (data.region) { |
| 61 | 42 | locationStr = data.region; |
| 43 | + if (data.country_name) { |
| 44 | + locationStr += `, ${data.country_name}`; |
| 45 | + } |
| 62 | 46 | } else if (data.country_name) { |
| 63 | 47 | locationStr = data.country_name; |
| 64 | 48 | } |
| 65 | 49 | |
| 66 | | - handleLocationFound(locationStr || 'Unknown'); |
| 50 | + setLocation(locationStr || 'Unknown'); |
| 51 | + setLocationObj(locationObj); // Store the structured object |
| 52 | + handleLocationFound(locationObj); |
| 67 | 53 | } catch (err) { |
| 68 | 54 | setError("Couldn't detect location. Try entering manually!"); |
| 69 | 55 | setLoading(false); |
@@ -75,68 +61,65 @@ function App() { |
| 75 | 61 | }; |
| 76 | 62 | |
| 77 | 63 | const handleLocationFound = (loc) => { |
| 78 | | - setLocation(loc); |
| 79 | | - |
| 80 | | - // Normalize the location for database lookup |
| 81 | | - const normalizedLoc = loc.trim() |
| 82 | | - .split(' ') |
| 83 | | - .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) |
| 84 | | - .join(' '); |
| 85 | | - |
| 86 | | - // Try exact match first, then try just the first word (for "Los Angeles, California" -> "California") |
| 87 | | - let roasts = roastDatabase[normalizedLoc]; |
| 88 | | - |
| 89 | | - if (!roasts && loc.includes(',')) { |
| 90 | | - // Try the state/country part after the comma |
| 91 | | - const parts = loc.split(','); |
| 92 | | - const statePart = parts[1].trim() |
| 93 | | - .split(' ') |
| 94 | | - .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) |
| 95 | | - .join(' '); |
| 96 | | - roasts = roastDatabase[statePart]; |
| 97 | | - } |
| 64 | + // Parse the location string if needed |
| 65 | + let parsedLocationObj = { city: null, state: null, country: null }; |
| 98 | 66 | |
| 99 | | - if (!roasts) { |
| 100 | | - // Try some common variations |
| 101 | | - const variations = { |
| 102 | | - 'Ny': 'New York', |
| 103 | | - 'Nyc': 'New York', |
| 104 | | - 'La': 'California', |
| 105 | | - 'Los Angeles': 'California', |
| 106 | | - 'San Francisco': 'California', |
| 107 | | - 'Sf': 'California', |
| 108 | | - 'Tx': 'Texas', |
| 109 | | - 'Va': 'Virginia', |
| 110 | | - 'Cali': 'California' |
| 111 | | - }; |
| 67 | + if (typeof loc === 'string') { |
| 68 | + // If it's a string, try to parse it |
| 69 | + const parts = loc.split(',').map(p => p.trim()); |
| 112 | 70 | |
| 113 | | - const variation = variations[normalizedLoc]; |
| 114 | | - if (variation) { |
| 115 | | - roasts = roastDatabase[variation]; |
| 71 | + if (parts.length === 1) { |
| 72 | + // Could be city, state, or country |
| 73 | + parsedLocationObj.city = parts[0]; |
| 74 | + } else if (parts.length === 2) { |
| 75 | + // Likely "City, State" or "City, Country" |
| 76 | + parsedLocationObj.city = parts[0]; |
| 77 | + parsedLocationObj.state = parts[1]; |
| 78 | + } else if (parts.length >= 3) { |
| 79 | + // "City, State, Country" format |
| 80 | + parsedLocationObj.city = parts[0]; |
| 81 | + parsedLocationObj.state = parts[1]; |
| 82 | + parsedLocationObj.country = parts[2]; |
| 116 | 83 | } |
| 84 | + } else if (typeof loc === 'object') { |
| 85 | + // If it's already an object, use it directly |
| 86 | + parsedLocationObj = loc; |
| 117 | 87 | } |
| 118 | 88 | |
| 119 | | - // Default to generic roasts if nothing found |
| 120 | | - roasts = roasts || roastDatabase.default; |
| 89 | + // Store the parsed object for reuse |
| 90 | + setLocationObj(parsedLocationObj); |
| 91 | + |
| 92 | + // Get roasts using the service |
| 93 | + const roasts = getRoastsForLocation(parsedLocationObj); |
| 94 | + |
| 95 | + if (roasts.length > 0) { |
| 96 | + const randomRoast = roasts[Math.floor(Math.random() * roasts.length)]; |
| 97 | + setCurrentRoast(randomRoast); |
| 98 | + } else { |
| 99 | + setCurrentRoast("Your location is so irrelevant, even our roast database gave up."); |
| 100 | + } |
| 121 | 101 | |
| 122 | | - const randomRoast = roasts[Math.floor(Math.random() * roasts.length)]; |
| 123 | | - setCurrentRoast(randomRoast); |
| 124 | 102 | setLoading(false); |
| 125 | 103 | }; |
| 126 | 104 | |
| 127 | 105 | const handleManualSubmit = (e) => { |
| 128 | 106 | e.preventDefault(); |
| 129 | 107 | if (manualInput.trim()) { |
| 130 | | - handleLocationFound(manualInput.trim()); |
| 108 | + const inputLocation = manualInput.trim(); |
| 109 | + setLocation(inputLocation); |
| 110 | + handleLocationFound(inputLocation); |
| 131 | 111 | setManualInput(''); |
| 132 | 112 | } |
| 133 | 113 | }; |
| 134 | 114 | |
| 135 | 115 | const getAnotherRoast = () => { |
| 136 | | - if (location) { |
| 137 | | - const roasts = roastDatabase[location] || roastDatabase.default; |
| 138 | | - const randomRoast = roasts[Math.floor(Math.random() * roasts.length)]; |
| 139 | | - setCurrentRoast(randomRoast); |
| 116 | + if (locationObj) { |
| 117 | + // Use the stored location object instead of parsing the display string |
| 118 | + const roasts = getRoastsForLocation(locationObj); |
| 119 | + if (roasts.length > 0) { |
| 120 | + const randomRoast = roasts[Math.floor(Math.random() * roasts.length)]; |
| 121 | + setCurrentRoast(randomRoast); |
| 122 | + } |
| 140 | 123 | } |
| 141 | 124 | }; |
| 142 | 125 | |