Add frontend POI management and travel time display

POIManager component in FilterPanel for creating/deleting POIs and
triggering distance calculations. PropertyCard shows travel time badges
(walk/cycle/transit) per POI. Map renders POI locations as red markers.
API client extended with POST body support for POI endpoints.
This commit is contained in:
Viktor Barzin 2026-02-08 13:16:32 +00:00
parent bb489c2032
commit 8509a0326f
No known key found for this signature in database
GPG key ID: 0EB088298288D958
9 changed files with 414 additions and 10 deletions

View file

@ -15,8 +15,8 @@ import { StreamingProgressBar } from './components/StreamingProgressBar';
import { Sheet, SheetContent, SheetTrigger } from './components/ui/sheet';
import { Button } from './components/ui/button';
import { Filter } from 'lucide-react';
import type { GeoJSONFeatureCollection, PropertyProperties, PropertyFeature } from '@/types';
import { refreshListings, fetchTasksForUser, streamListingGeoJSON, type StreamingProgress } from '@/services';
import type { GeoJSONFeatureCollection, PropertyProperties, PropertyFeature, POI } from '@/types';
import { refreshListings, fetchTasksForUser, streamListingGeoJSON, fetchUserPOIs, type StreamingProgress } from '@/services';
function App() {
const [listingData, setListingData] = useState<GeoJSONFeatureCollection | null>(null);
@ -30,6 +30,7 @@ function App() {
const [mobileFilterOpen, setMobileFilterOpen] = useState(false);
const [highlightedProperty, setHighlightedProperty] = useState<string | null>(null);
const [streamingProgress, setStreamingProgress] = useState<StreamingProgress | null>(null);
const [userPOIs, setUserPOIs] = useState<POI[]>([]);
// Ref to track accumulated features during streaming
const accumulatedFeaturesRef = useRef<PropertyFeature[]>([]);
@ -70,6 +71,12 @@ function App() {
});
}, [user, taskID]);
// Load user's POIs
useEffect(() => {
if (!user) return;
fetchUserPOIs(user).then(setUserPOIs).catch(() => {});
}, [user]);
// Load listings function - used by both auto-load and manual submit
const loadListings = useCallback(async (parameters: ParameterValues) => {
if (!user) return;
@ -221,6 +228,7 @@ function App() {
listingData={listingData}
queryParameters={queryParameters}
onPropertyClick={handlePropertyClick}
pois={userPOIs}
/>
</div>
)}
@ -243,6 +251,14 @@ function App() {
setTaskID(null);
};
const handlePOITaskCreated = (taskId: string) => {
setTaskID(taskId);
// Refresh POI list in case new ones were created
if (user) {
fetchUserPOIs(user).then(setUserPOIs).catch(() => {});
}
};
return (
<div className="h-screen flex flex-col overflow-hidden">
{/* Header */}
@ -261,6 +277,8 @@ function App() {
onMetricChange={handleMetricChange}
isLoading={isLoading}
listingCount={listingData?.features.length}
user={user}
onTaskCreated={handlePOITaskCreated}
/>
</div>
@ -278,6 +296,8 @@ function App() {
onMetricChange={handleMetricChange}
isLoading={isLoading}
listingCount={listingData?.features.length}
user={user}
onTaskCreated={handlePOITaskCreated}
/>
</SheetContent>
</Sheet>