perfect-postcode/frontend/src/components/map/ExternalSearchLinks.tsx
2026-05-11 21:38:26 +01:00

73 lines
2.9 KiB
TypeScript

import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import type { FeatureFilters } from '../../types';
import {
buildRightmoveExactPostcodeRedirectUrl,
buildPropertySearchUrls,
H3_RADIUS_MILES,
type HexagonLocation,
} from '../../lib/external-search';
import outcodeIds from '../../lib/rightmove-outcodes.json';
const rightmoveOutcodes = outcodeIds as Record<string, string>;
function getRightmoveLocationId(postcode: string | undefined): string | undefined {
if (!postcode) return undefined;
const outcode = postcode.trim().split(/\s+/)[0].toUpperCase();
const id = rightmoveOutcodes[outcode];
return id ? `OUTCODE^${id}` : undefined;
}
export default function ExternalSearchLinks({
location,
filters,
}: {
location: HexagonLocation;
filters: FeatureFilters;
}) {
const { t } = useTranslation();
const rightmoveLocationId = getRightmoveLocationId(location.postcode);
const urls = useMemo(
() => buildPropertySearchUrls({ location, filters, rightmoveLocationId }),
[location, filters, rightmoveLocationId]
);
const rightmoveHref = useMemo(() => {
if (!urls?.rightmove) return null;
if (!location.isPostcode || !location.postcode) return urls.rightmove;
return buildRightmoveExactPostcodeRedirectUrl(location.postcode, urls.rightmove);
}, [location.isPostcode, location.postcode, urls?.rightmove]);
const radiusMiles = location.isPostcode ? 0 : (H3_RADIUS_MILES[location.resolution] ?? 1);
const label = radiusMiles === 0 ? t('externalSearch.exact') : `${radiusMiles}mi radius`;
if (!urls) return null;
const linkClass =
'flex-1 text-center text-xs py-1.5 px-2 rounded border border-warm-200 dark:border-warm-700 bg-white dark:bg-warm-800 text-teal-600 dark:text-teal-400 hover:bg-warm-50 dark:hover:bg-warm-700 font-medium';
const disabledClass =
'flex-1 text-center text-xs py-1.5 px-2 rounded border border-warm-200 dark:border-warm-700 bg-white dark:bg-warm-800 text-warm-400 dark:text-warm-500 font-medium cursor-default';
return (
<div className="p-3 border-b border-warm-200 dark:border-navy-700">
<h3 className="text-xs font-semibold text-warm-500 dark:text-warm-400 uppercase tracking-wider mb-2">
{t('externalSearch.searchOn', { radius: label })}
</h3>
<div className="flex flex-wrap gap-2">
{rightmoveHref ? (
<a href={rightmoveHref} target="_blank" rel="noopener noreferrer" className={linkClass}>
Rightmove
</a>
) : (
<span className={disabledClass} title={t('externalSearch.outcodeNotRecognised')}>
Rightmove
</span>
)}
<a href={urls.onthemarket} target="_blank" rel="noopener noreferrer" className={linkClass}>
OnTheMarket
</a>
<a href={urls.zoopla} target="_blank" rel="noopener noreferrer" className={linkClass}>
Zoopla
</a>
</div>
</div>
);
}