()
| 309 | useEffect(() => { |
| 310 | if (!effectiveField) return; |
| 311 | const fetchWeatherData = async () => { |
| 312 | setLoading(true); |
| 313 | try { |
| 314 | const { lat, lng } = getFieldCenter(effectiveField); |
| 315 | const start = format(startDate, "yyyy-MM-dd"); |
| 316 | const end = format(endDate, "yyyy-MM-dd"); |
| 317 | const [weatherRes, soilRes] = await Promise.all([ |
| 318 | 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`), |
| 319 | 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`)] |
| 320 | ); |
| 321 | const data = await weatherRes.json(); |
| 322 | const soilData = await soilRes.json(); |
| 323 | |
| 324 | if (data.daily) { |
| 325 | const daily = data.daily.time.map((date: string, i: number) => ({ |
| 326 | date, label: format(new Date(date + "T00:00:00"), "MMM dd"), |
| 327 | precipitation: data.daily.precipitation_sum[i] || 0, |
| 328 | tempMax: data.daily.temperature_2m_max[i], tempMin: data.daily.temperature_2m_min[i], |
| 329 | evap: data.daily.et0_fao_evapotranspiration[i] || 0 |
| 330 | })); |
| 331 | const monthMap = new Map<string, {precip: number;count: number;tMax: number;tMin: number;evap: number;}>(); |
| 332 | daily.forEach((d: any) => { |
| 333 | const key = format(new Date(d.date + "T00:00:00"), "MMM yyyy"); |
| 334 | const m = monthMap.get(key) || { precip: 0, count: 0, tMax: -999, tMin: 999, evap: 0 }; |
| 335 | 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; |
| 336 | monthMap.set(key, m); |
| 337 | }); |
| 338 | let accumulated = 0; |
| 339 | const monthly = Array.from(monthMap.entries()).map(([month, v]) => { |
| 340 | accumulated += v.precip; |
| 341 | 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 }; |
| 342 | }); |
| 343 | setMonthlyData(monthly); |
| 344 | setDailyData(daily.filter((_: any, i: number) => i % 2 === 0)); |
| 345 | } |
| 346 | if (soilData.daily) { |
| 347 | const soilMonthMap = new Map<string, {shallow: number;deep: number;count: number;}>(); |
| 348 | soilData.daily.time.forEach((date: string, i: number) => { |
| 349 | const key = format(new Date(date + "T00:00:00"), "MMM yyyy"); |
| 350 | const m = soilMonthMap.get(key) || { shallow: 0, deep: 0, count: 0 }; |
| 351 | m.shallow += soilData.daily.soil_moisture_0_to_7cm_mean?.[i] || 0; |
| 352 | m.deep += soilData.daily.soil_moisture_7_to_28cm_mean?.[i] || 0; |
| 353 | m.count++;soilMonthMap.set(key, m); |
| 354 | }); |
| 355 | const soilMonthly = Array.from(soilMonthMap.entries()).map(([month, v]) => ({ |
| 356 | month: month.split(" ")[0], shallow: Math.round(v.shallow / v.count * 1000) / 10, deep: Math.round(v.deep / v.count * 1000) / 10 |
| 357 | })); |
| 358 | setSoilMoistureData(soilMonthly); |
| 359 | } |
| 360 | } catch (e) {console.error("Failed to fetch weather data", e);} finally |
| 361 | {setLoading(false);} |
| 362 | }; |
| 363 | fetchWeatherData(); |
| 364 | }, [startDate, endDate, effectiveField]); |
| 365 |
no test coverage detected