import React, { useMemo, useState } from 'react'; import { Property } from '../types'; interface PropertiesPaneProps { properties: Property[]; total: number; loading: boolean; hexagonId: string | null; onLoadMore: () => void; onClose: () => void; } type SortBy = 'price' | 'size' | 'energy'; export function PropertiesPane({ properties, total, loading, hexagonId, onLoadMore, onClose, }: PropertiesPaneProps) { const [sortBy, setSortBy] = useState('price'); // Sort properties const sortedProperties = useMemo(() => { return [...properties].sort((a, b) => { switch (sortBy) { case 'price': return ((b.latest_price as number) || 0) - ((a.latest_price as number) || 0); case 'size': return ((b.total_floor_area as number) || 0) - ((a.total_floor_area as number) || 0); case 'energy': return (a.current_energy_rating || 'Z').localeCompare(b.current_energy_rating || 'Z'); } }); }, [properties, sortBy]); if (!hexagonId) { return (
Click a hexagon to view properties
); } return (
{/* Header */}

Properties in Hexagon

Showing {properties.length} of {total} properties

{/* Sort controls */}
{/* Properties list */}
{loading && properties.length === 0 ? (
Loading...
) : ( <> {sortedProperties.map((property, idx) => ( ))} {properties.length < total && ( )} )}
); } // Property card component showing all fields function PropertyCard({ property }: { property: Property }) { const formatNumber = (value: number | undefined, decimals = 0): string => { if (value === undefined) return ''; return decimals > 0 ? value.toFixed(decimals) : Math.round(value).toLocaleString(); }; return (
{/* Address */}
{property.address || 'Unknown Address'}
{property.postcode}
{/* Price */} {property.latest_price && (
£{formatNumber(property.latest_price as number)} {property.price_per_sqm && ( {' '} (£{formatNumber(property.price_per_sqm as number)}/m²) )}
)} {/* Property details grid */}
{property.property_type && (
Type: {property.property_type}
)} {property.built_form && (
Form: {property.built_form}
)} {property.total_floor_area && (
Area:{' '} {formatNumber(property.total_floor_area as number)}m²
)} {property.number_habitable_rooms && (
Rooms:{' '} {formatNumber(property.number_habitable_rooms as number)}
)} {property.current_energy_rating && (
Energy: {property.current_energy_rating}
)} {property.potential_energy_rating && (
Potential: {property.potential_energy_rating}
)} {property.construction_age_band !== undefined && (
Built (age):{' '} {formatNumber(property.construction_age_band as number)}
)} {/* Journey times */} {property.public_transport_easy_minutes && (
PT (easy):{' '} {formatNumber(property.public_transport_easy_minutes as number)}min
)} {property.public_transport_quick_minutes && (
PT (quick):{' '} {formatNumber(property.public_transport_quick_minutes as number)}min
)} {property.cycling_minutes && (
Cycling:{' '} {formatNumber(property.cycling_minutes as number)}min
)} {/* Deprivation scores */} {property.income_score !== undefined && (
Income:{' '} {formatNumber(property.income_score as number, 1)}
)} {property.employment_score !== undefined && (
Employment:{' '} {formatNumber(property.employment_score as number, 1)}
)} {property.education_score !== undefined && (
Education:{' '} {formatNumber(property.education_score as number, 1)}
)} {property.health_score !== undefined && (
Health:{' '} {formatNumber(property.health_score as number, 1)}
)} {property.crime_score !== undefined && (
Crime:{' '} {formatNumber(property.crime_score as number, 1)}
)}
); }