/** * Hail Recon integration hook. * * USE_MOCK = true → returns mock data from mockStore (local dev, no API key needed) * USE_MOCK = false → calls /api/hail-proxy which forwards to Hail Recon with Basic Auth * * Flip USE_MOCK to false once: * 1. HAIL_RECON_ACCESS_KEY + HAIL_RECON_ACCESS_SECRET are set in Vercel env vars * 2. Vercel KV is connected to the project */ import { useState, useEffect, useCallback } from 'react'; import { MOCK_HAIL_HISTORY } from '../data/mockStore'; const USE_MOCK = false; // ── Helpers ────────────────────────────────────────────────────────────────── export function hailSeverity(sizeInches) { if (!sizeInches || sizeInches < 0.75) return 'none'; if (sizeInches < 1.00) return 'trace'; if (sizeInches < 1.50) return 'moderate'; if (sizeInches < 2.00) return 'significant'; return 'severe'; } export function hailSeverityColor(sizeInches, mode = 'text') { const s = hailSeverity(sizeInches); const map = { none: { text: 'text-zinc-400', bg: 'bg-zinc-100 dark:bg-zinc-800', border: 'border-zinc-200 dark:border-white/10' }, trace: { text: 'text-yellow-600 dark:text-yellow-400', bg: 'bg-yellow-50 dark:bg-yellow-500/10', border: 'border-yellow-200 dark:border-yellow-500/20' }, moderate: { text: 'text-orange-600 dark:text-orange-400', bg: 'bg-orange-50 dark:bg-orange-500/10', border: 'border-orange-200 dark:border-orange-500/20' }, significant: { text: 'text-red-600 dark:text-red-400', bg: 'bg-red-50 dark:bg-red-500/10', border: 'border-red-200 dark:border-red-500/20' }, severe: { text: 'text-red-700 dark:text-red-300', bg: 'bg-red-100 dark:bg-red-500/20', border: 'border-red-300 dark:border-red-500/30' }, }; return map[s]?.[mode] ?? map.none[mode]; } export function daysAgo(dateStr) { const diff = Date.now() - new Date(dateStr).getTime(); return Math.floor(diff / (1000 * 60 * 60 * 24)); } // ── API calls (real path) ──────────────────────────────────────────────────── async function proxyGet(endpoint, params = {}) { const qs = new URLSearchParams({ endpoint, ...params }).toString(); const res = await fetch(`/api/hail-proxy?${qs}`); if (!res.ok) throw new Error(`Hail proxy error: ${res.status}`); return res.json(); } async function proxyPost(endpoint, body) { const res = await fetch(`/api/hail-proxy?endpoint=${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) throw new Error(`Hail proxy error: ${res.status}`); return res.json(); } // ── Main hook: hail history for a single lead ──────────────────────────────── export function useHailHistory(leadId, lat, lng, months = 12) { const [history, setHistory] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { if (!leadId) return; let cancelled = false; setLoading(true); setError(null); const fetch_ = async () => { try { let data; if (USE_MOCK) { await new Promise(r => setTimeout(r, 400)); data = MOCK_HAIL_HISTORY[leadId] ?? []; } else { data = await proxyGet('ImpactDatesForLatLong', { Lat: lat, Long: lng, Months: months, }); if (!Array.isArray(data)) data = []; } if (!cancelled) setHistory(data); } catch (e) { if (!cancelled) setError(e.message); } finally { if (!cancelled) setLoading(false); } }; fetch_(); return () => { cancelled = true; }; }, [leadId, lat, lng, months]); const hitCount = history?.length ?? 0; const lastHit = history?.[0] ?? null; const maxSize = history?.reduce((m, e) => Math.max(m, e.hailSize ?? 0), 0) ?? 0; return { history, loading, error, hitCount, lastHit, maxSize }; } // ── Register an address for monitoring ────────────────────────────────────── export function useRegisterAddress() { return useCallback(async (lead) => { if (USE_MOCK) { console.log('[HailRecon mock] registerAddress:', lead?.property?.address); return { success: true, AddressMarker_id: Math.floor(Math.random() * 9000000) + 1000000 }; } try { const p = lead.property ?? {}; const c = lead.customer ?? {}; const urgencyToSize = { emergency: 3, high: 2, standard: 1 }; return await proxyPost('AddressMonitoringImport2g', { street: p.address ?? '', city: p.city ?? 'Plano', state: p.state ?? 'TX', zip: p.zip ?? '', customer_name: c.name ?? '', customer_phone: c.phone ?? '', customer_email: c.email ?? '', comment1: '#planoRealtyCRM', comment2: lead.leadType ?? '', address_monitoring_size: urgencyToSize[lead.urgency] ?? 1, status: 'Monitoring', integration_partner: 2, latitude: p.lat ?? null, longitude: p.lng ?? null, external_key: lead.id ?? null, }); } catch (e) { console.warn('[HailRecon] registerAddress failed (non-fatal):', e.message); return null; } }, []); } // ── Bulk hail summaries for a list of leads (dispatch queue) ───────────────── export function useHailSummaries(leads) { const [summaries, setSummaries] = useState({}); const [loading, setLoading] = useState(true); useEffect(() => { if (!leads?.length) { setLoading(false); return; } let cancelled = false; const fetchAll = async () => { setLoading(true); try { const results = {}; if (USE_MOCK) { await new Promise(r => setTimeout(r, 600)); leads.forEach(lead => { const events = MOCK_HAIL_HISTORY[lead.id] ?? []; const lastHit = events[0] ?? null; const maxSize = events.reduce((m, e) => Math.max(m, e.hailSize ?? 0), 0); results[lead.id] = { events, hitCount: events.length, lastHit, maxSize }; }); } else { await Promise.all(leads.map(async (lead) => { try { const p = lead.property ?? {}; const events = await proxyGet('ImpactDatesForLatLong', { Lat: p.lat, Long: p.lng, Months: 12, }); const arr = Array.isArray(events) ? events : []; const lastHit = arr[0] ?? null; const maxSize = arr.reduce((m, e) => Math.max(m, e.hailSize ?? 0), 0); results[lead.id] = { events: arr, hitCount: arr.length, lastHit, maxSize }; } catch { results[lead.id] = { events: [], hitCount: 0, lastHit: null, maxSize: 0 }; } })); } if (!cancelled) setSummaries(results); } finally { if (!cancelled) setLoading(false); } }; fetchAll(); return () => { cancelled = true; }; }, [leads]); return { summaries, loading }; }