weather icons
This commit is contained in:
@@ -496,3 +496,24 @@ router.get('/conditions/suitable/:propertyId', async (req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
||||||
|
// Icon proxy to avoid external CSP/mixed-content issues
|
||||||
|
// @route GET /api/weather/icon/:code
|
||||||
|
// @desc Proxy OpenWeather icon by code (e.g., 10d) with optional size=2x
|
||||||
|
// @access Public (icons only)
|
||||||
|
router.get('/icon/:code', async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const { code } = req.params;
|
||||||
|
const size = (req.query.size === '2x') ? '@2x' : '';
|
||||||
|
if (!code || !/^[0-9]{2}[dn]$/.test(code)) {
|
||||||
|
return res.status(400).send('invalid icon code');
|
||||||
|
}
|
||||||
|
const url = `https://openweathermap.org/img/wn/${code}${size}.png`;
|
||||||
|
const response = await require('axios').get(url, { responseType: 'arraybuffer', timeout: 5000 });
|
||||||
|
res.set('Content-Type', 'image/png');
|
||||||
|
res.set('Cache-Control', 'public, max-age=21600'); // 6 hours
|
||||||
|
return res.status(200).send(Buffer.from(response.data));
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(502).send('icon fetch failed');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -72,7 +72,12 @@ const Weather = () => {
|
|||||||
<div className="text-sm text-gray-600">No coordinates set</div>
|
<div className="text-sm text-gray-600">No coordinates set</div>
|
||||||
) : weatherMap[p.id]?.weather ? (
|
) : weatherMap[p.id]?.weather ? (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<img alt="" width="50" height="50" src={`https://openweathermap.org/img/wn/${weatherMap[p.id].weather.current.icon}@2x.png`} />
|
<img
|
||||||
|
alt=""
|
||||||
|
width="50"
|
||||||
|
height="50"
|
||||||
|
src={`${(process.env.REACT_APP_API_URL || '')}/weather/icon/${weatherMap[p.id].weather.current.icon}?size=2x`}
|
||||||
|
/>
|
||||||
<div className="ml-3">
|
<div className="ml-3">
|
||||||
<div className="text-xl font-bold">{weatherMap[p.id].weather.current.temperature}°F</div>
|
<div className="text-xl font-bold">{weatherMap[p.id].weather.current.temperature}°F</div>
|
||||||
<div className="text-sm text-gray-700">{weatherMap[p.id].weather.current.conditions}</div>
|
<div className="text-sm text-gray-700">{weatherMap[p.id].weather.current.conditions}</div>
|
||||||
@@ -93,7 +98,13 @@ const Weather = () => {
|
|||||||
<div className="font-medium">
|
<div className="font-medium">
|
||||||
{new Date(d.date).toLocaleDateString(undefined, { weekday: 'short' })}
|
{new Date(d.date).toLocaleDateString(undefined, { weekday: 'short' })}
|
||||||
</div>
|
</div>
|
||||||
<img alt="" className="mx-auto" width="40" height="40" src={`https://openweathermap.org/img/wn/${d.icon}@2x.png`} />
|
<img
|
||||||
|
alt=""
|
||||||
|
className="mx-auto"
|
||||||
|
width="40"
|
||||||
|
height="40"
|
||||||
|
src={`${(process.env.REACT_APP_API_URL || '')}/weather/icon/${d.icon}?size=2x`}
|
||||||
|
/>
|
||||||
<div>{d.temperatureHigh}° / {d.temperatureLow}°</div>
|
<div>{d.temperatureHigh}° / {d.temperatureLow}°</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user