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:
parent
8a5d1b3787
commit
2fdafdcb64
1 changed files with 54 additions and 22 deletions
|
|
@ -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)}
|
||||
>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue