Auto-trigger WALK + BICYCLE distance calculation on POI creation

After creating a POI, automatically trigger WALK and BICYCLE distance
calculations (cheap OSRM batch API). TRANSIT is excluded since it uses
the expensive OTP backend — users trigger it manually via the calculator
button. Failure is non-fatal: the POI is still created and calculation
can be retried manually.
This commit is contained in:
Viktor Barzin 2026-02-08 14:51:34 +00:00
parent 8a5d1b3787
commit 2fdafdcb64
No known key found for this signature in database
GPG key ID: 0EB088298288D958

View file

@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { MapPin, Plus, Trash2, Calculator, Loader2 } from 'lucide-react';
import { MapPin, Plus, Trash2, Calculator, Loader2, Crosshair } from 'lucide-react';
import { Button } from './ui/button';
import { Input } from './ui/input';
import type { AuthUser } from '@/auth/types';
@ -10,9 +10,11 @@ interface POIManagerProps {
user: AuthUser;
listingType: 'RENT' | 'BUY';
onTaskCreated?: (taskId: string) => void;
pickedLocation?: { lat: number; lng: number } | null;
onStartPicking?: () => void;
}
export function POIManager({ user, listingType, onTaskCreated }: POIManagerProps) {
export function POIManager({ user, listingType, onTaskCreated, pickedLocation, onStartPicking }: POIManagerProps) {
const [pois, setPois] = useState<POI[]>([]);
const [isAdding, setIsAdding] = useState(false);
const [name, setName] = useState('');
@ -26,6 +28,14 @@ export function POIManager({ user, listingType, onTaskCreated }: POIManagerProps
fetchUserPOIs(user).then(setPois).catch(() => {});
}, [user]);
// When a location is picked from the map, populate lat/lng
useEffect(() => {
if (pickedLocation) {
setLat(String(pickedLocation.lat));
setLng(String(pickedLocation.lng));
}
}, [pickedLocation]);
const handleCreate = async () => {
if (!name || !lat || !lng) return;
try {
@ -41,6 +51,16 @@ export function POIManager({ user, listingType, onTaskCreated }: POIManagerProps
setAddress('');
setLat('');
setLng('');
// Auto-trigger WALK + BICYCLE distance calculation (cheap OSRM).
// TRANSIT (expensive OTP) is excluded — user triggers manually.
try {
const result = await triggerPOICalculation(
user, poi.id, ['WALK', 'BICYCLE'], listingType
);
onTaskCreated?.(result.task_id);
} catch {
// Non-fatal: POI created successfully, calculation can be retried manually.
}
} catch {
// silently fail
}
@ -83,6 +103,7 @@ export function POIManager({ user, listingType, onTaskCreated }: POIManagerProps
<Button
variant="ghost"
size="sm"
type="button"
className="h-6 w-6 p-0"
onClick={() => handleCalculate(poi.id)}
disabled={calculating === poi.id}
@ -96,6 +117,7 @@ export function POIManager({ user, listingType, onTaskCreated }: POIManagerProps
<Button
variant="ghost"
size="sm"
type="button"
className="h-6 w-6 p-0 text-destructive hover:text-destructive"
onClick={() => handleDelete(poi.id)}
>
@ -139,33 +161,42 @@ export function POIManager({ user, listingType, onTaskCreated }: POIManagerProps
onChange={e => setAddress(e.target.value)}
className="h-7 text-xs"
/>
<div className="grid grid-cols-2 gap-2">
<Input
type="number"
step="any"
placeholder="Latitude"
value={lat}
onChange={e => setLat(e.target.value)}
className="h-7 text-xs"
/>
<Input
type="number"
step="any"
placeholder="Longitude"
value={lng}
onChange={e => setLng(e.target.value)}
className="h-7 text-xs"
/>
</div>
{lat && lng ? (
<div className="flex items-center gap-2 p-1.5 bg-muted rounded text-xs text-muted-foreground">
<MapPin className="h-3 w-3 shrink-0" />
<span className="truncate">{parseFloat(lat).toFixed(5)}, {parseFloat(lng).toFixed(5)}</span>
<Button
variant="ghost"
size="sm"
type="button"
className="h-5 px-1.5 text-xs ml-auto"
onClick={() => { onStartPicking?.(); }}
>
Change
</Button>
</div>
) : (
<Button
variant="outline"
size="sm"
type="button"
className="w-full h-7 text-xs"
onClick={() => onStartPicking?.()}
>
<Crosshair className="h-3.5 w-3.5 mr-1" />
Pick on Map
</Button>
)}
<div className="flex gap-2">
<Button size="sm" className="h-7 text-xs flex-1" onClick={handleCreate}>
<Button size="sm" type="button" className="h-7 text-xs flex-1" onClick={handleCreate} disabled={!lat || !lng}>
Save
</Button>
<Button
size="sm"
variant="outline"
type="button"
className="h-7 text-xs"
onClick={() => setIsAdding(false)}
onClick={() => { setIsAdding(false); setLat(''); setLng(''); }}
>
Cancel
</Button>
@ -175,6 +206,7 @@ export function POIManager({ user, listingType, onTaskCreated }: POIManagerProps
<Button
variant="outline"
size="sm"
type="button"
className="w-full h-7 text-xs"
onClick={() => setIsAdding(true)}
>