83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import { useState } from 'react';
|
|
import axios from 'axios';
|
|
import './App.css';
|
|
import FileUpload from './components/FileUpload';
|
|
import FilterPanel from './components/FilterPanel';
|
|
import MapDisplay from './components/MapDisplay';
|
|
|
|
// Define types for our state
|
|
export interface FilterOptions {
|
|
[key: string]: string[];
|
|
}
|
|
|
|
export interface HeatmapPoint {
|
|
plz: string;
|
|
lat: number;
|
|
lon: number;
|
|
count: number;
|
|
}
|
|
|
|
function App() {
|
|
const [filters, setFilters] = useState<FilterOptions>({});
|
|
const [heatmapData, setHeatmapData] = useState<HeatmapPoint[]>([]);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const handleUploadSuccess = (newFilters: FilterOptions) => {
|
|
setFilters(newFilters);
|
|
setHeatmapData([]); // Clear previous heatmap data
|
|
setError(null);
|
|
// Automatically fetch data with no filters on successful upload
|
|
handleFilterChange({});
|
|
};
|
|
|
|
const handleFilterChange = async (selectedFilters: FilterOptions) => {
|
|
setIsLoading(true);
|
|
setError(null);
|
|
try {
|
|
const response = await axios.post('http://localhost:8002/api/heatmap', {
|
|
filters: selectedFilters,
|
|
});
|
|
setHeatmapData(response.data);
|
|
} catch (error: any) {
|
|
if (axios.isAxiosError(error) && error.response) {
|
|
setError(`Failed to fetch heatmap data: ${error.response.data.detail || error.message}`);
|
|
} else {
|
|
setError(`Failed to fetch heatmap data: ${error.message}`);
|
|
}
|
|
setHeatmapData([]); // Clear data on error
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="App">
|
|
<header className="App-header">
|
|
<h1>German PLZ Heatmap Tool</h1>
|
|
</header>
|
|
<main className="App-main">
|
|
<div className="control-panel">
|
|
<FileUpload
|
|
onUploadSuccess={handleUploadSuccess}
|
|
setIsLoading={setIsLoading}
|
|
setError={setError}
|
|
/>
|
|
<FilterPanel
|
|
filters={filters}
|
|
onFilterChange={handleFilterChange}
|
|
isLoading={isLoading}
|
|
/>
|
|
</div>
|
|
<div className="map-container">
|
|
{isLoading && <p>Loading map data...</p>}
|
|
{error && <p className="error">{error}</p>}
|
|
<MapDisplay heatmapData={heatmapData} />
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default App;
|