This commit is contained in:
Andras Schmelczer 2026-05-14 20:42:48 +01:00
parent 273d7a83ee
commit 084117cea8
48 changed files with 2283 additions and 890 deletions

View file

@ -1,4 +1,4 @@
import { useMemo, useState, useCallback } from 'react';
import { useMemo, useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { Property } from '../../types';
import { formatDuration, formatAge, formatNumber, formatTransactionDate } from '../../lib/format';
@ -7,7 +7,6 @@ import InfoPopup from '../ui/InfoPopup';
import { SearchInput } from '../ui/SearchInput';
import { EmptyState } from '../ui/EmptyState';
import { InfoIcon } from '../ui/icons';
import { BookmarkIcon } from '../ui/icons/BookmarkIcon';
import { ts } from '../../i18n/server';
interface PropertiesPaneProps {
@ -17,10 +16,6 @@ interface PropertiesPaneProps {
hexagonId: string | null;
onLoadMore: () => void;
onNavigateToSource?: (slug: string) => void;
onSaveProperty?: (property: Property) => void;
onUnsaveProperty?: (id: string) => void;
isPropertySaved?: (address?: string, postcode?: string) => boolean;
getSavedPropertyId?: (address?: string, postcode?: string) => string | undefined;
}
export function PropertiesPane({
@ -30,15 +25,15 @@ export function PropertiesPane({
hexagonId,
onLoadMore,
onNavigateToSource,
onSaveProperty,
onUnsaveProperty,
isPropertySaved,
getSavedPropertyId,
}: PropertiesPaneProps) {
const { t } = useTranslation();
const [search, setSearch] = useState('');
const [showInfo, setShowInfo] = useState(false);
useEffect(() => {
setSearch('');
}, [hexagonId]);
const filtered = useMemo(() => {
const query = search.trim().toLowerCase();
return query
@ -100,14 +95,7 @@ export function PropertiesPane({
) : (
<>
{filtered.map((property, idx) => (
<PropertyCard
key={idx}
property={property}
onSave={onSaveProperty}
onUnsave={onUnsaveProperty}
isSaved={isPropertySaved?.(property.address, property.postcode)}
savedId={getSavedPropertyId?.(property.address, property.postcode)}
/>
<PropertyCard key={idx} property={property} />
))}
{properties.length < total && (
<button
@ -151,27 +139,8 @@ function PropertyLoadingSkeleton() {
);
}
function PropertyCard({
property,
onSave,
onUnsave,
isSaved,
savedId,
}: {
property: Property;
onSave?: (property: Property) => void;
onUnsave?: (id: string) => void;
isSaved?: boolean;
savedId?: string;
}) {
function PropertyCard({ property }: { property: Property }) {
const { t } = useTranslation();
const handleToggleSave = useCallback(() => {
if (isSaved && savedId && onUnsave) {
onUnsave(savedId);
} else if (onSave) {
onSave(property);
}
}, [isSaved, savedId, onSave, onUnsave, property]);
const price = getNum(property, 'Last known price');
const estimatedPrice = getNum(property, 'Estimated current price');
const pricePerSqm = getNum(property, 'Price per sqm');
@ -197,19 +166,6 @@ function PropertyCard({
)}
</div>
</div>
{onSave && (
<button
onClick={handleToggleSave}
className={`shrink-0 p-1 rounded ${
isSaved
? 'text-teal-600 dark:text-teal-400'
: 'text-warm-300 dark:text-warm-600 hover:text-warm-500 dark:hover:text-warm-400'
}`}
title={isSaved ? t('propertyCard.unsaveProperty') : t('propertyCard.saveProperty')}
>
<BookmarkIcon className="w-4 h-4" filled={isSaved} />
</button>
)}
</div>
{property.property_sub_type && (