diff --git a/web/src/App.tsx b/web/src/App.tsx
index dfda205..71d86bd 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -207,6 +207,8 @@ export default function App() {
)}
{!deals.isFetching && !deals.error && !deals.data && (
diff --git a/web/src/components/DealsTable.tsx b/web/src/components/DealsTable.tsx
index b2f42de..9dd5cc4 100644
--- a/web/src/components/DealsTable.tsx
+++ b/web/src/components/DealsTable.tsx
@@ -4,10 +4,13 @@ import { formatCurrencyILS, formatDate, formatNumber } from "../lib/utils";
interface Props {
deals: Deal[];
resolvedAddress?: string;
+ searchedBlock?: string;
+ searchedPlot?: string;
}
// Extract street name from a Govmap address string like "הילדסהיימר 14, ירושלים".
-// Takes all leading tokens that contain no digits.
+// Takes all leading tokens that contain no digits. Used as fallback only —
+// for parcel searches Govmap echoes back "גוש N חלקה M" with no street info.
function streetFromAddress(address: string | undefined): string | null {
if (!address) return null;
const tokens = address.split(/[\s,]+/);
@@ -19,6 +22,31 @@ function streetFromAddress(address: string | undefined): string | null {
return parts.length ? parts.join(" ") : null;
}
+// Find the street name of the searched parcel by picking the deal with the
+// closest parcelNum within the same gush. Cadastral parcel numbers are usually
+// assigned along street frontage, so the nearest plot is almost always the
+// same street.
+function streetByClosestParcel(
+ deals: Deal[],
+ block: string | undefined,
+ plot: string | undefined
+): string | null {
+ if (!plot) return null;
+ const target = parseInt(plot, 10);
+ if (!Number.isFinite(target)) return null;
+ const blockNum = block ? parseInt(block, 10) : null;
+ let best: { dist: number; street: string } | null = null;
+ for (const d of deals) {
+ if (!d.streetNameHeb || d.parcelNum == null) continue;
+ if (blockNum !== null && d.gushNum !== blockNum) continue;
+ const dist = Math.abs((d.parcelNum as number) - target);
+ if (!best || dist < best.dist) {
+ best = { dist, street: d.streetNameHeb };
+ }
+ }
+ return best?.street ?? null;
+}
+
function proximityLabel(deal: Deal, inferredStreet: string | null): string {
if (!deal.deal_source) return "—";
if (deal.deal_source === "same_building") return "אותו בניין";
@@ -36,7 +64,7 @@ function proximityClass(deal: Deal, inferredStreet: string | null): string {
return "bg-slate-100 text-slate-700";
}
-export function DealsTable({ deals, resolvedAddress }: Props) {
+export function DealsTable({ deals, resolvedAddress, searchedBlock, searchedPlot }: Props) {
if (!deals.length) {
return (
@@ -45,7 +73,11 @@ export function DealsTable({ deals, resolvedAddress }: Props) {
);
}
- const inferredStreet = streetFromAddress(resolvedAddress);
+ // Prefer closest-parcel inference (works for both address and block_plot
+ // searches); fall back to parsing the resolved autocomplete text.
+ const inferredStreet =
+ streetByClosestParcel(deals, searchedBlock, searchedPlot) ??
+ streetFromAddress(resolvedAddress);
return (