locate adress on map and find hail risk
This commit is contained in:
@@ -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 };
|
||||
}
|
||||
Reference in New Issue
Block a user