From 54bdcac14ada70209344f755cde71ca8214c219a Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sun, 8 Feb 2026 18:50:13 +0000 Subject: [PATCH] Run alembic migrations on startup, fix User model, add POI travel sorting and streaming options --- Dockerfile | 2 +- frontend/src/components/ListView.tsx | 32 ++++++++++++++++++----- frontend/src/services/streamingService.ts | 6 ++++- frontend/tsconfig.app.tsbuildinfo | 2 +- models/user.py | 2 +- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 570190e..465d0b5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,4 +42,4 @@ ENV PATH="/app/.venv/bin:$PATH" COPY . . EXPOSE 5001 -CMD ["uvicorn", "api.app:app", "--host", "0.0.0.0", "--port", "5001"] +CMD ["sh", "-c", "alembic upgrade head && uvicorn api.app:app --host 0.0.0.0 --port 5001"] diff --git a/frontend/src/components/ListView.tsx b/frontend/src/components/ListView.tsx index 790146a..69f8151 100644 --- a/frontend/src/components/ListView.tsx +++ b/frontend/src/components/ListView.tsx @@ -3,15 +3,16 @@ import { ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react'; import { Virtuoso } from 'react-virtuoso'; import { Button } from './ui/button'; import { PropertyCard } from './PropertyCard'; -import type { GeoJSONFeatureCollection, PropertyFeature, PropertyProperties } from '@/types'; +import type { GeoJSONFeatureCollection, PropertyFeature, PropertyProperties, POIDistanceInfo } from '@/types'; -type SortField = 'total_price' | 'qmprice' | 'qm' | 'rooms' | 'last_seen'; +type SortField = 'total_price' | 'qmprice' | 'qm' | 'rooms' | 'last_seen' | 'poi_travel'; type SortOrder = 'asc' | 'desc'; interface ListViewProps { listingData: GeoJSONFeatureCollection; onPropertyClick?: (property: PropertyProperties, coordinates: [number, number]) => void; highlightedPropertyUrl?: string | null; + poiMetricSelection?: { poiId: number; travelMode: string } | null; } interface SortConfig { @@ -19,7 +20,7 @@ interface SortConfig { order: SortOrder; } -const SORT_OPTIONS: { field: SortField; label: string }[] = [ +const BASE_SORT_OPTIONS: { field: SortField; label: string }[] = [ { field: 'total_price', label: 'Price' }, { field: 'qmprice', label: '£/m²' }, { field: 'qm', label: 'Size' }, @@ -27,7 +28,7 @@ const SORT_OPTIONS: { field: SortField; label: string }[] = [ { field: 'last_seen', label: 'Last Seen' }, ]; -export function ListView({ listingData, onPropertyClick, highlightedPropertyUrl }: ListViewProps) { +export function ListView({ listingData, onPropertyClick, highlightedPropertyUrl, poiMetricSelection }: ListViewProps) { const [sortConfig, setSortConfig] = useState({ field: 'qmprice', order: 'asc' }); // Calculate average price per sqm for "good deal" indicator @@ -40,6 +41,13 @@ export function ListView({ listingData, onPropertyClick, highlightedPropertyUrl : 0; }, [listingData]); + const sortOptions = useMemo(() => { + if (poiMetricSelection) { + return [...BASE_SORT_OPTIONS, { field: 'poi_travel' as SortField, label: 'Travel' }]; + } + return BASE_SORT_OPTIONS; + }, [poiMetricSelection]); + // Sort features const sortedFeatures = useMemo(() => { const features = [...listingData.features]; @@ -69,6 +77,18 @@ export function ListView({ listingData, onPropertyClick, highlightedPropertyUrl aValue = new Date(a.properties.last_seen).getTime(); bValue = new Date(b.properties.last_seen).getTime(); break; + case 'poi_travel': { + const getTravel = (f: PropertyFeature): number => { + if (!poiMetricSelection) return Infinity; + const match = f.properties.poi_distances?.find( + (d: POIDistanceInfo) => d.poi_id === poiMetricSelection.poiId && d.travel_mode === poiMetricSelection.travelMode, + ); + return match?.duration_seconds ?? Infinity; + }; + aValue = getTravel(a); + bValue = getTravel(b); + break; + } default: return 0; } @@ -80,7 +100,7 @@ export function ListView({ listingData, onPropertyClick, highlightedPropertyUrl }); return features; - }, [listingData.features, sortConfig]); + }, [listingData.features, sortConfig, poiMetricSelection]); const handleSort = (field: SortField) => { setSortConfig((prev) => ({ @@ -109,7 +129,7 @@ export function ListView({ listingData, onPropertyClick, highlightedPropertyUrl {/* Sort controls */}
Sort: - {SORT_OPTIONS.map((option) => ( + {sortOptions.map((option) => (