Auto-reload listings on task completion and show all POIs in detail view
Thread onTaskCompleted callback from TaskIndicator through Header to App.tsx so listings auto-refresh when a background task (e.g. POI distance calculation) completes. Add AllPOIDistances component to PropertyCard that shows all user POIs with travel times or — placeholder for missing modes.
This commit is contained in:
parent
01dae5dfbd
commit
81d31eaecf
5 changed files with 227 additions and 88 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { ExternalLink, Bed, Maximize2, PoundSterling, Clock, Building, Footprints, Bike, Train } from 'lucide-react';
|
||||
import { Button } from './ui/button';
|
||||
import type { PropertyProperties, POIDistanceInfo } from '@/types';
|
||||
import type { PropertyProperties, POIDistanceInfo, POI } from '@/types';
|
||||
|
||||
function formatDuration(seconds: number): string {
|
||||
const minutes = Math.round(seconds / 60);
|
||||
|
|
@ -47,11 +47,43 @@ function POIDistanceBadges({ distances }: { distances: POIDistanceInfo[] }) {
|
|||
);
|
||||
}
|
||||
|
||||
const TRAVEL_MODES: Array<'WALK' | 'BICYCLE' | 'TRANSIT'> = ['WALK', 'BICYCLE', 'TRANSIT'];
|
||||
|
||||
function AllPOIDistances({ pois, distances }: { pois: POI[]; distances?: POIDistanceInfo[] }) {
|
||||
// Index distances by poi_id + travel_mode for O(1) lookup
|
||||
const distMap = new Map<string, POIDistanceInfo>();
|
||||
if (distances) {
|
||||
for (const d of distances) {
|
||||
distMap.set(`${d.poi_id}_${d.travel_mode}`, d);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap gap-1.5 mt-1.5">
|
||||
{pois.map(poi => (
|
||||
<div key={poi.id} className="flex items-center gap-1 text-xs text-muted-foreground bg-muted/50 px-1.5 py-0.5 rounded">
|
||||
<span className="font-medium">{poi.name}:</span>
|
||||
{TRAVEL_MODES.map(mode => {
|
||||
const dist = distMap.get(`${poi.id}_${mode}`);
|
||||
return (
|
||||
<span key={mode} className="flex items-center gap-0.5" title={`${mode} to ${poi.name}`}>
|
||||
<TravelModeIcon mode={mode} />
|
||||
{dist ? formatDuration(dist.duration_seconds) : '—'}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface PropertyCardProps {
|
||||
property: PropertyProperties;
|
||||
variant?: 'compact' | 'full';
|
||||
isHighlighted?: boolean;
|
||||
avgPricePerSqm?: number;
|
||||
allPOIs?: POI[];
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +92,7 @@ export function PropertyCard({
|
|||
variant = 'compact',
|
||||
isHighlighted = false,
|
||||
avgPricePerSqm,
|
||||
allPOIs,
|
||||
onClick,
|
||||
}: PropertyCardProps) {
|
||||
const lastSeenDate = property.last_seen.split('T')[0];
|
||||
|
|
@ -218,12 +251,17 @@ export function PropertyCard({
|
|||
</div>
|
||||
|
||||
{/* POI Distances */}
|
||||
{property.poi_distances && property.poi_distances.length > 0 && (
|
||||
{allPOIs && allPOIs.length > 0 ? (
|
||||
<div className="mt-3 pt-3 border-t">
|
||||
<div className="text-xs font-medium text-muted-foreground mb-1">Travel times</div>
|
||||
<AllPOIDistances pois={allPOIs} distances={property.poi_distances} />
|
||||
</div>
|
||||
) : property.poi_distances && property.poi_distances.length > 0 ? (
|
||||
<div className="mt-3 pt-3 border-t">
|
||||
<div className="text-xs font-medium text-muted-foreground mb-1">Travel times</div>
|
||||
<POIDistanceBadges distances={property.poi_distances} />
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
{/* Price history */}
|
||||
{property.price_history.length > 1 && (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue