[31b88f42] Add staff locations and reach visualization to Heatmap Tool

This commit is contained in:
2026-03-09 13:44:15 +00:00
parent 47973445dc
commit f9e16bc8ad
3 changed files with 196 additions and 10 deletions

View File

@@ -28,6 +28,18 @@ export interface HeatmapPoint {
attributes_summary?: Record<string, string[]>;
}
export interface StaffLocation {
name: string;
plz: string;
lat: number;
lon: number;
}
export interface StaffData {
sales: StaffLocation[];
technicians: StaffLocation[];
}
export type MapMode = 'points' | 'heatmap';
function App() {
@@ -42,6 +54,22 @@ function App() {
const [availableColumns, setAvailableColumns] = useState<string[]>([]);
const [tooltipColumns, setTooltipColumns] = useState<TooltipColumn[]>([]);
const [staffData, setStaffData] = useState<StaffData>({ sales: [], technicians: [] });
const [showSales, setShowSales] = useState(false);
const [showTechnicians, setShowTechnicians] = useState(false);
const [travelRadius, setTravelRadius] = useState(50); // In km
useEffect(() => {
const fetchStaffLocations = async () => {
try {
const response = await axios.get('/heatmap/api/staff-locations');
setStaffData(response.data);
} catch (err) {
console.error("Failed to fetch staff locations:", err);
}
};
fetchStaffLocations();
}, []);
const handleUploadSuccess = (response: any) => {
setError(null);
@@ -153,6 +181,34 @@ function App() {
Heatmap
</label>
</div>
<div className="staff-toggles" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px' }}>
<input type="checkbox" checked={showSales} onChange={(e) => setShowSales(e.target.checked)} />
Show Sales Reps
</label>
<label style={{ display: 'block', marginBottom: '15px' }}>
<input type="checkbox" checked={showTechnicians} onChange={(e) => setShowTechnicians(e.target.checked)} />
Show Technicians
</label>
</div>
{(showSales || showTechnicians) && (
<div className="radius-control" style={{ marginBottom: '20px' }}>
<label htmlFor="travel-radius">Travel Radius: {travelRadius} km</label>
<input
type="range"
id="travel-radius"
min="10"
max="200"
step="5"
value={travelRadius}
onChange={(e) => setTravelRadius(parseInt(e.target.value))}
style={{ width: '100%' }}
/>
</div>
)}
<label htmlFor="radius-slider">Marker Size: {radiusMultiplier.toFixed(1)}x</label>
<input
type="range"
@@ -180,6 +236,10 @@ function App() {
radiusMultiplier={radiusMultiplier}
viewMode={viewMode}
tooltipColumns={tooltipColumns}
staffData={staffData}
showSales={showSales}
showTechnicians={showTechnicians}
travelRadius={travelRadius}
/>
)}
</div>