locate adress on map and find hail risk

This commit is contained in:
Mayur Shinde
2026-06-09 16:15:21 +05:30
parent 716d096fc8
commit 110790d5ae
8 changed files with 522 additions and 21 deletions
@@ -0,0 +1,87 @@
/**
* useWizardHailRisk — produces a frozen hail-risk snapshot for the wizard.
*
* Pipeline (all read-only against existing services):
* 1. geocode the address (module-local geocode.js → Nominatim)
* 2. GET /api/storm-history (EXISTING storm module endpoint — not modified)
* 3. run computeHailRisk() (module-local Poisson model, spec §6)
*
* Returns { loading, error, property, snapshot }. The caller freezes `snapshot`
* into the session (spec §12 hail_risk_snapshots) so the report stays immutable.
*/
import { useState, useEffect } from 'react';
import { geocodeAddress } from '../api/geocode';
import { computeHailRisk } from '../engine/hailProbability';
export function useWizardHailRisk({ address, property, enabled = true, stormSettings = {} }) {
const [loading, setLoading] = useState(enabled);
const [error, setError] = useState(null);
const [resolvedProperty, setResolvedProperty] = useState(property || null);
const [snapshot, setSnapshot] = useState(null);
const radiusMiles = stormSettings.radiusMiles ?? 20;
// storm-history caps months at 60 (5 years); window honesty is stored in the snapshot.
const months = 60;
const windowYears = months / 12;
useEffect(() => {
if (!enabled) return;
let cancelled = false;
setLoading(true);
setError(null);
(async () => {
try {
// 1. Resolve coordinates (reuse stored property if already geocoded).
let prop = property;
if (!prop || prop.lat == null || prop.lon == null) {
prop = await geocodeAddress(address);
}
if (cancelled) return;
setResolvedProperty(prop);
// 2. Existing keyless storm endpoint (read-only).
let hailCount = 0;
let maxHail = null;
let lastEventDate = null;
let source = 'NOAA / IEM Local Storm Reports';
try {
const res = await fetch(
`/api/storm-history?lat=${prop.lat}&lng=${prop.lon}&months=${months}&radiusMi=${Math.min(radiusMiles, 50)}`
);
if (res.ok) {
const data = await res.json();
hailCount = data?.summary?.byType?.hail ?? 0;
maxHail = data?.summary?.maxHail ?? null;
lastEventDate = data?.summary?.lastEvent?.date ?? null;
}
} catch {
// Leave defaults (count 0) — computeHailRisk handles the empty case honestly.
}
if (cancelled) return;
// 3. Conservative Poisson model.
const snap = computeHailRisk({
eventCount: hailCount,
windowYears,
radiusMiles,
geocodeConfidence: prop.confidence,
maxHailInches: maxHail,
lastEventDate,
source,
generatedAt: new Date().toISOString(),
});
if (!cancelled) setSnapshot(snap);
} catch (e) {
if (!cancelled) setError(e.message || 'Could not load storm history.');
} finally {
if (!cancelled) setLoading(false);
}
})();
return () => { cancelled = true; };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [address, enabled, radiusMiles]);
return { loading, error, property: resolvedProperty, snapshot };
}