diff --git a/backend/src/app.js b/backend/src/app.js index 8a6be6b..27f1dd2 100644 --- a/backend/src/app.js +++ b/backend/src/app.js @@ -35,7 +35,13 @@ app.use(helmet({ scriptSrc: ["'self'", "'unsafe-inline'", "https://maps.googleapis.com"], styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"], fontSrc: ["'self'", "https://fonts.gstatic.com"], - imgSrc: ["'self'", "data:", "https://maps.googleapis.com", "https://maps.gstatic.com"], + imgSrc: [ + "'self'", + "data:", + "https://maps.googleapis.com", + "https://maps.gstatic.com", + "https://openweathermap.org" + ], connectSrc: ["'self'", "https://api.openweathermap.org"] } } diff --git a/backend/src/routes/weather.js b/backend/src/routes/weather.js index 2e19349..5a8f286 100644 --- a/backend/src/routes/weather.js +++ b/backend/src/routes/weather.js @@ -220,6 +220,7 @@ router.get('/:propertyId/forecast', async (req, res, next) => { windSpeed: [], precipitation: 0, conditions: [], + icons: [], timestamps: [] }; } @@ -229,6 +230,7 @@ router.get('/:propertyId/forecast', async (req, res, next) => { dailyForecast[date].windSpeed.push(item.wind?.speed || 0); dailyForecast[date].precipitation += item.rain?.['3h'] || 0; dailyForecast[date].conditions.push(item.weather[0].description); + dailyForecast[date].icons.push(item.weather[0].icon); dailyForecast[date].timestamps.push(new Date(item.dt * 1000)); }); @@ -246,6 +248,7 @@ router.get('/:propertyId/forecast', async (req, res, next) => { maxWindSpeed: Math.round(Math.max(...windSpeeds)), totalPrecipitation: Math.round(day.precipitation * 100) / 100, conditions: day.conditions[0], // Use first condition of the day + icon: day.icons[0], timestamps: day.timestamps }; }).slice(0, 5); // Limit to 5 days diff --git a/frontend/src/pages/Weather/Weather.js b/frontend/src/pages/Weather/Weather.js index 9621788..d13d282 100644 --- a/frontend/src/pages/Weather/Weather.js +++ b/frontend/src/pages/Weather/Weather.js @@ -3,7 +3,7 @@ import { propertiesAPI, weatherAPI } from '../../services/api'; const Weather = () => { const [properties, setProperties] = useState([]); - const [weatherMap, setWeatherMap] = useState({}); // propertyId -> weather + const [weatherMap, setWeatherMap] = useState({}); // propertyId -> { weather, forecast } const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -20,14 +20,26 @@ const Weather = () => { .filter(p => p.latitude && p.longitude) .map(p => p.id); - const results = await Promise.allSettled(ids.map(id => weatherAPI.getCurrent(id))); + // Current weather + const currentResults = await Promise.allSettled(ids.map(id => weatherAPI.getCurrent(id))); const map = {}; - results.forEach((r, idx) => { + currentResults.forEach((r, idx) => { const id = ids[idx]; if (r.status === 'fulfilled') { - map[id] = r.value.data.data.weather; + map[id] = { weather: r.value.data.data.weather }; } }); + + // 5-day forecast + const forecastResults = await Promise.allSettled(ids.map(id => weatherAPI.getForecast(id))); + forecastResults.forEach((r, idx) => { + const id = ids[idx]; + if (r.status === 'fulfilled') { + map[id] = map[id] || {}; + map[id].forecast = r.value.data.data.forecast; + } + }); + setWeatherMap(map); setError(null); } catch (e) { @@ -58,20 +70,35 @@ const Weather = () => { {!p.latitude || !p.longitude ? (