fix: handle missing isochron better

This commit is contained in:
Jan-Henrik 2026-03-06 23:36:27 +01:00
parent 43a1c71dd1
commit 09d23e6666

View file

@ -40,6 +40,7 @@ export default function HomePage() {
// Pin / location rating
const [pinLocation, setPinLocation] = useState<{ lat: number; lng: number } | null>(null);
const [pinData, setPinData] = useState<LocationScoreData | null>(null);
const [pinScoreError, setPinScoreError] = useState(false);
const [pinAddress, setPinAddress] = useState<string | undefined>(undefined);
const [pinEstateValue, setPinEstateValue] = useState<number | null>(null);
const [pinEstatePercentile, setPinEstatePercentile] = useState<number | null>(null);
@ -100,11 +101,13 @@ export default function HomePage() {
useEffect(() => {
if (!pinLocation || !selectedCity) {
setPinData(null);
setPinScoreError(false);
setPinAddress(undefined);
return;
}
let cancelled = false;
setPinScoreError(false);
const params = new URLSearchParams({
lat: String(pinLocation.lat),
@ -128,14 +131,15 @@ export default function HomePage() {
.then(([scoreData, address]) => {
if (cancelled) return;
if (scoreData?.error) {
// No grid data for this location — clear the pin so the skeleton doesn't persist.
setPinLocation(null);
// No grid data for this mode — keep the pin (isochrone may still show) but
// display an error state instead of an infinite loading skeleton.
setPinScoreError(true);
return;
}
setPinData(scoreData as LocationScoreData);
setPinAddress(address);
})
.catch(() => { if (!cancelled) setPinLocation(null); });
.catch(() => { if (!cancelled) setPinScoreError(true); });
return () => { cancelled = true; };
}, [pinLocation, selectedCity, mode, threshold, profile]);
@ -252,6 +256,7 @@ export default function HomePage() {
// Clear pin when profile changes so scores are re-fetched with new profile
setPinLocation(null);
setPinData(null);
setPinScoreError(false);
setPinAddress(undefined);
setPinEstateValue(null);
setPinEstatePercentile(null);
@ -262,6 +267,7 @@ export default function HomePage() {
function handleLocationClick(lat: number, lng: number, estateValue: number | null) {
setPinLocation({ lat, lng });
setPinData(null);
setPinScoreError(false);
setPinAddress(undefined);
setPinEstateValue(estateValue);
setPinEstatePercentile(null);
@ -272,6 +278,7 @@ export default function HomePage() {
function handlePinClose() {
setPinLocation(null);
setPinData(null);
setPinScoreError(false);
setPinAddress(undefined);
setPinEstateValue(null);
setPinEstatePercentile(null);
@ -351,7 +358,21 @@ export default function HomePage() {
hasPinData={!!pinData}
/>
{pinLocation && !pinData && (
{pinLocation && !pinData && pinScoreError && (
<div className="absolute bottom-8 right-4 z-20 bg-white rounded-xl shadow-lg border border-gray-100 w-72 p-4">
<button
onClick={handlePinClose}
className="absolute top-3 right-3 text-gray-300 hover:text-gray-500 text-xl leading-none"
aria-label="Close"
>×</button>
<p className="text-sm text-gray-500 text-center py-4">
No score data for this mode yet.<br />
<span className="text-xs text-gray-400">Re-run ingest to compute new modes.</span>
</p>
</div>
)}
{pinLocation && !pinData && !pinScoreError && (
<div className="absolute bottom-8 right-4 z-20 bg-white rounded-xl shadow-lg border border-gray-100 w-72 p-4">
<button
onClick={handlePinClose}