Add filter info
This commit is contained in:
parent
01ec17ff04
commit
f7d586a1e9
5 changed files with 682 additions and 234 deletions
|
|
@ -100,122 +100,100 @@ export function PropertiesPane({
|
|||
);
|
||||
}
|
||||
|
||||
function formatDuration(d: string): string {
|
||||
if (d === 'F') return 'Freehold';
|
||||
if (d === 'L') return 'Leasehold';
|
||||
return d;
|
||||
}
|
||||
|
||||
function formatAge(value: number): string {
|
||||
// construction_age_band is a midpoint year, e.g. 1935
|
||||
if (value >= 1000) return `~${Math.round(value)}`;
|
||||
return Math.round(value).toString();
|
||||
}
|
||||
|
||||
// Helper to get a numeric value from a property, trying multiple field names
|
||||
function getNum(property: Property, ...keys: string[]): number | undefined {
|
||||
for (const key of keys) {
|
||||
const v = property[key];
|
||||
if (v !== undefined && v !== null && typeof v === 'number') return v;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Property card component showing all fields
|
||||
function PropertyCard({ property }: { property: Property }) {
|
||||
const formatNumber = (value: number | undefined, decimals = 0): string => {
|
||||
const fmt = (value: number | undefined, decimals = 0): string => {
|
||||
if (value === undefined) return '';
|
||||
return decimals > 0 ? value.toFixed(decimals) : Math.round(value).toLocaleString();
|
||||
};
|
||||
|
||||
const price = getNum(property, 'Last known price', 'latest_price');
|
||||
const pricePerSqm = getNum(property, 'Price per sqm', 'price_per_sqm');
|
||||
const floorArea = getNum(property, 'Total floor area (sqm)', 'total_floor_area');
|
||||
const rooms = getNum(property, 'Rooms (including bedrooms & bathrooms)', 'number_habitable_rooms');
|
||||
const age = getNum(property, 'Approximate construction age', 'construction_age_band');
|
||||
|
||||
return (
|
||||
<div className="p-4 border-b border-gray-100 hover:bg-gray-50">
|
||||
{/* Address */}
|
||||
{/* Address & postcode */}
|
||||
<div className="font-semibold">{property.address || 'Unknown Address'}</div>
|
||||
<div className="text-sm text-gray-600">{property.postcode}</div>
|
||||
|
||||
{/* Price */}
|
||||
{property.latest_price && (
|
||||
{price !== undefined && (
|
||||
<div className="mt-2 text-lg font-bold text-green-700">
|
||||
£{formatNumber(property.latest_price as number)}
|
||||
{property.price_per_sqm && (
|
||||
£{fmt(price)}
|
||||
{pricePerSqm !== undefined && (
|
||||
<span className="text-sm font-normal text-gray-600">
|
||||
{' '}
|
||||
(£{formatNumber(property.price_per_sqm as number)}/m²)
|
||||
(£{fmt(pricePerSqm)}/m²)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Property details grid */}
|
||||
<div className="mt-2 grid grid-cols-2 gap-2 text-sm">
|
||||
<div className="mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-sm">
|
||||
{property.property_type && (
|
||||
<div>
|
||||
<span className="text-gray-600">Type:</span> {property.property_type}
|
||||
<span className="text-gray-500">Type:</span> {property.property_type}
|
||||
</div>
|
||||
)}
|
||||
{property.built_form && (
|
||||
<div>
|
||||
<span className="text-gray-600">Form:</span> {property.built_form}
|
||||
<span className="text-gray-500">Built form:</span> {property.built_form}
|
||||
</div>
|
||||
)}
|
||||
{property.total_floor_area && (
|
||||
{property.duration && (
|
||||
<div>
|
||||
<span className="text-gray-600">Area:</span>{' '}
|
||||
{formatNumber(property.total_floor_area as number)}m²
|
||||
<span className="text-gray-500">Tenure:</span> {formatDuration(property.duration)}
|
||||
</div>
|
||||
)}
|
||||
{property.number_habitable_rooms && (
|
||||
{floorArea !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-600">Rooms:</span>{' '}
|
||||
{formatNumber(property.number_habitable_rooms as number)}
|
||||
<span className="text-gray-500">Floor area:</span> {fmt(floorArea)}m²
|
||||
</div>
|
||||
)}
|
||||
{rooms !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-500">Rooms:</span> {fmt(rooms)}
|
||||
</div>
|
||||
)}
|
||||
{age !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-500">Built:</span> {formatAge(age)}
|
||||
</div>
|
||||
)}
|
||||
{property.current_energy_rating && (
|
||||
<div>
|
||||
<span className="text-gray-600">Energy:</span> {property.current_energy_rating}
|
||||
<span className="text-gray-500">EPC rating:</span> {property.current_energy_rating}
|
||||
</div>
|
||||
)}
|
||||
{property.potential_energy_rating && (
|
||||
<div>
|
||||
<span className="text-gray-600">Potential:</span> {property.potential_energy_rating}
|
||||
</div>
|
||||
)}
|
||||
{property.construction_age_band !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-600">Built (age):</span>{' '}
|
||||
{formatNumber(property.construction_age_band as number)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Journey times */}
|
||||
{property.public_transport_easy_minutes && (
|
||||
<div>
|
||||
<span className="text-gray-600">PT (easy):</span>{' '}
|
||||
{formatNumber(property.public_transport_easy_minutes as number)}min
|
||||
</div>
|
||||
)}
|
||||
{property.public_transport_quick_minutes && (
|
||||
<div>
|
||||
<span className="text-gray-600">PT (quick):</span>{' '}
|
||||
{formatNumber(property.public_transport_quick_minutes as number)}min
|
||||
</div>
|
||||
)}
|
||||
{property.cycling_minutes && (
|
||||
<div>
|
||||
<span className="text-gray-600">Cycling:</span>{' '}
|
||||
{formatNumber(property.cycling_minutes as number)}min
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Deprivation scores */}
|
||||
{property.income_score !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-600">Income:</span>{' '}
|
||||
{formatNumber(property.income_score as number, 1)}
|
||||
</div>
|
||||
)}
|
||||
{property.employment_score !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-600">Employment:</span>{' '}
|
||||
{formatNumber(property.employment_score as number, 1)}
|
||||
</div>
|
||||
)}
|
||||
{property.education_score !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-600">Education:</span>{' '}
|
||||
{formatNumber(property.education_score as number, 1)}
|
||||
</div>
|
||||
)}
|
||||
{property.health_score !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-600">Health:</span>{' '}
|
||||
{formatNumber(property.health_score as number, 1)}
|
||||
</div>
|
||||
)}
|
||||
{property.crime_score !== undefined && (
|
||||
<div>
|
||||
<span className="text-gray-600">Crime:</span>{' '}
|
||||
{formatNumber(property.crime_score as number, 1)}
|
||||
<span className="text-gray-500">EPC potential:</span>{' '}
|
||||
{property.potential_energy_rating}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue