Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
.App-header {
.App {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}

.App-header {
background-color: #222;
padding: 20px;
color: white;
text-align: center;
}
margin-bottom: 20px;
}

.zip-search-field {
margin-bottom: 20px;
}

.zip-search-field input {
padding: 5px;
font-size: 16px;
}

.city {
background-color: #f0f0f0;
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px;
margin-bottom: 15px;
}

.city h2 {
margin-top: 0;
color: #333;
}

.error {
color: red;
font-weight: bold;
margin-bottom: 15px;
}
94 changes: 81 additions & 13 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,97 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import "./App.css";

function City(props) {
return <div>This is the City component</div>;
// City component: Displays information for a single city
function City({ city }) {
return (
<div className="city">
<h2>{city.City}, {city.State}</h2>
<p>State: {city.State}</p>
<p>Location: ({city.Lat}, {city.Long})</p>
<p>Population (estimated): {city.EstimatedPopulation}</p>
<p>Total Wages: {city.TotalWages}</p>
</div>
);
}

function ZipSearchField(props) {
return <div>This is the ZipSearchField component</div>;
// ZipSearchField component: Handles user input for zip code
function ZipSearchField({ onZipChange }) {
return (
<div className="zip-search-field">
<label htmlFor="zip-code">Zip Code: </label>
<input
type="text"
id="zip-code"
onChange={(e) => {
// console.log("Input changed:", e.target.value); // Debugging: Log input changes
onZipChange(e.target.value);
}}
placeholder="Enter a zip code"
/>
</div>
);
}

// Main App component
function App() {
// State hooks
const [zipCode, setZipCode] = useState(""); // Stores the current zip code
const [cities, setCities] = useState([]); // Stores the list of cities
const [error, setError] = useState(""); // Stores any error messages

// Effect hook: Runs when zipCode changes
useEffect(() => {
console.log("Zip code changed:", zipCode); // Debugging: Log zip code changes

// Async function to fetch data from the API
const fetchData = async () => {
// Only fetch if zipCode is exactly 5 characters
if (zipCode.length !== 5) {
setCities([]);
setError("");
return;
}

// Inner async function to handle the actual API call
const fetchCities = async () => {
const response = await fetch(`https://ctp-zip-code-api.onrender.com/zip/${zipCode}`);
if (!response.ok) {
throw new Error('No results found');
}
return response.json();
};

// Call fetchCities and handle the result
await fetchCities()
.then(data => {
console.log("Fetched data:", data); // Debugging: Log fetched data
setCities(data);
setError("");
})
.catch(err => {
console.error("Error fetching data:", err); // Debugging: Log any errors
setCities([]);
setError(err.message);
});
};

// Call the fetchData function
fetchData();
}, [zipCode]); // This effect runs whenever zipCode changes

// Render the component
return (
<div className="App">
<div className="App-header">
<h1>Zip Code Search</h1>
</div>
<div className="mx-auto" style={{ maxWidth: 400 }}>
<ZipSearchField />
<div>
<City />
<City />
</div>
</div>
<ZipSearchField onZipChange={setZipCode} />
{error && <p className="error">{error}</p>}
{cities.map((city, index) => (
<City key={index} city={city} />
))}
</div>
);
}

export default App;
export default App;