()
| 152 | // Fetch weather data |
| 153 | useEffect(() => { |
| 154 | const fetchWeatherData = async () => { |
| 155 | setLoading(true); |
| 156 | try { |
| 157 | const { lat, lng } = getFieldCenter(field); |
| 158 | const start = format(startDate, "yyyy-MM-dd"); |
| 159 | const end = format(endDate, "yyyy-MM-dd"); |
| 160 | const [weatherRes, soilRes] = await Promise.all([ |
| 161 | fetch(`https://archive-api.open-meteo.com/v1/archive?latitude=${lat}&longitude=${lng}&start_date=${start}&end_date=${end}&daily=precipitation_sum,temperature_2m_max,temperature_2m_min,et0_fao_evapotranspiration`), |
| 162 | fetch(`https://archive-api.open-meteo.com/v1/archive?latitude=${lat}&longitude=${lng}&start_date=${start}&end_date=${end}&daily=soil_moisture_0_to_7cm_mean,soil_moisture_7_to_28cm_mean`), |
| 163 | ]); |
| 164 | const data = await weatherRes.json(); |
| 165 | const soilData = await soilRes.json(); |
| 166 | |
| 167 | if (data.daily) { |
| 168 | const daily = data.daily.time.map((date: string, i: number) => ({ |
| 169 | date, label: format(new Date(date + "T00:00:00"), "MMM dd"), |
| 170 | precipitation: data.daily.precipitation_sum[i] || 0, |
| 171 | tempMax: data.daily.temperature_2m_max[i], tempMin: data.daily.temperature_2m_min[i], |
| 172 | evap: data.daily.et0_fao_evapotranspiration[i] || 0, |
| 173 | })); |
| 174 | const monthMap = new Map<string, { precip: number; count: number; tMax: number; tMin: number; evap: number }>(); |
| 175 | daily.forEach((d: any) => { |
| 176 | const key = format(new Date(d.date + "T00:00:00"), "MMM yyyy"); |
| 177 | const m = monthMap.get(key) || { precip: 0, count: 0, tMax: -999, tMin: 999, evap: 0 }; |
| 178 | m.precip += d.precipitation; m.count++; m.tMax = Math.max(m.tMax, d.tempMax ?? -999); m.tMin = Math.min(m.tMin, d.tempMin ?? 999); m.evap += d.evap; |
| 179 | monthMap.set(key, m); |
| 180 | }); |
| 181 | let accumulated = 0; |
| 182 | const monthly = Array.from(monthMap.entries()).map(([month, v]) => { |
| 183 | accumulated += v.precip; |
| 184 | return { month: month.split(" ")[0], precipitation: Math.round(v.precip * 10) / 10, accumulated: Math.round(accumulated * 10) / 10, tempMax: Math.round(v.tMax), tempMin: Math.round(v.tMin), evapotranspiration: Math.round(v.evap * 10) / 10 }; |
| 185 | }); |
| 186 | setMonthlyData(monthly); |
| 187 | setDailyData(daily.filter((_: any, i: number) => i % 2 === 0)); |
| 188 | } |
| 189 | if (soilData.daily) { |
| 190 | const soilMonthMap = new Map<string, { shallow: number; deep: number; count: number }>(); |
| 191 | soilData.daily.time.forEach((date: string, i: number) => { |
| 192 | const key = format(new Date(date + "T00:00:00"), "MMM yyyy"); |
| 193 | const m = soilMonthMap.get(key) || { shallow: 0, deep: 0, count: 0 }; |
| 194 | m.shallow += soilData.daily.soil_moisture_0_to_7cm_mean?.[i] || 0; |
| 195 | m.deep += soilData.daily.soil_moisture_7_to_28cm_mean?.[i] || 0; |
| 196 | m.count++; soilMonthMap.set(key, m); |
| 197 | }); |
| 198 | const soilMonthly = Array.from(soilMonthMap.entries()).map(([month, v]) => ({ |
| 199 | month: month.split(" ")[0], shallow: Math.round(v.shallow / v.count * 1000) / 10, deep: Math.round(v.deep / v.count * 1000) / 10, |
| 200 | })); |
| 201 | setSoilMoistureData(soilMonthly); |
| 202 | } |
| 203 | } catch (e) { console.error("Failed to fetch weather data", e); } |
| 204 | finally { setLoading(false); } |
| 205 | }; |
| 206 | fetchWeatherData(); |
| 207 | }, [startDate, endDate, field.id]); |
| 208 |
no test coverage detected