({ field, startDate, endDate, compact = false, gradientIdSuffix = "" }: FieldComparisonColumnProps)
| 77 | } |
| 78 | |
| 79 | const FieldComparisonColumn = ({ field, startDate, endDate, compact = false, gradientIdSuffix = "" }: FieldComparisonColumnProps) => { |
| 80 | const [monthlyData, setMonthlyData] = useState<any[]>([]); |
| 81 | const [dailyData, setDailyData] = useState<any[]>([]); |
| 82 | const [soilMoistureData, setSoilMoistureData] = useState<any[]>([]); |
| 83 | const [loading, setLoading] = useState(false); |
| 84 | const [geeData, setGeeData] = useState<any>(null); |
| 85 | const [geeLoading, setGeeLoading] = useState(false); |
| 86 | const [ndviTimeSeries, setNdviTimeSeries] = useState<any>(null); |
| 87 | const [ndviTsLoading, setNdviTsLoading] = useState(false); |
| 88 | |
| 89 | // Fetch GEE analytics |
| 90 | useEffect(() => { |
| 91 | const cached = getFreshLocalCacheValue<any>(GEE_ANALYTICS_CACHE_KEY, field.id, QUERY_CACHE_TTL_MS); |
| 92 | if (cached) { |
| 93 | setGeeData(cached); |
| 94 | return; |
| 95 | } |
| 96 | const fetchGee = async () => { |
| 97 | setGeeLoading(true); |
| 98 | try { |
| 99 | const polygon = field.coordinates[0]; |
| 100 | const { data, error } = await supabase.functions.invoke("gee-analytics", { |
| 101 | body: { polygon, analyses: ["land_use", "vegetation", "suitability"] }, |
| 102 | }); |
| 103 | if (error) throw error; |
| 104 | if (hasGeeAnalyticsPayload(data)) { |
| 105 | setGeeData(data); |
| 106 | setLocalCache(GEE_ANALYTICS_CACHE_KEY, field.id, data); |
| 107 | } else if (isFallbackPayload(data)) { |
| 108 | setGeeData(cached ?? null); |
| 109 | } else { |
| 110 | setGeeData(null); |
| 111 | } |
| 112 | } catch (e) { |
| 113 | console.error("GEE analytics error:", e); |
| 114 | setGeeData(cached ?? null); |
| 115 | } finally { setGeeLoading(false); } |
| 116 | }; |
| 117 | fetchGee(); |
| 118 | }, [field.id]); |
| 119 | |
| 120 | // Fetch NDVI time-series |
| 121 | useEffect(() => { |
| 122 | const cacheKey = `ts-${field.id}`; |
| 123 | const cached = getFreshLocalCacheValue<any>(GEE_ANALYTICS_CACHE_KEY, cacheKey, QUERY_CACHE_TTL_MS); |
| 124 | if (cached) { |
| 125 | setNdviTimeSeries(cached); |
| 126 | return; |
| 127 | } |
| 128 | const fetchTs = async () => { |
| 129 | setNdviTsLoading(true); |
| 130 | try { |
| 131 | const polygon = field.coordinates[0]; |
| 132 | const { data, error } = await supabase.functions.invoke("ndvi-timeseries", { |
| 133 | body: { polygon }, |
| 134 | }); |
| 135 | if (error) throw error; |
| 136 | if (hasNdviPayload(data)) { |
nothing calls this directly
no test coverage detected