|
|
|
@@ -0,0 +1,69 @@
|
|
|
|
|
const { convertWeatherSnapshot } = require('../../../../data/weather-units');
|
|
|
|
|
|
|
|
|
|
function buildDefaultWeatherLocation() {
|
|
|
|
|
return { id: null, enabled: 1, name: '', location_label: '', latitude: '', longitude: '', timezone: 'Europe/London', provider: 'open-meteo', temperature_unit: 'celsius', wind_unit: 'kmh', precipitation_unit: 'mm', update_interval_value: 30, update_interval_unit: 'minutes' };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function weatherIconForCode(code) {
|
|
|
|
|
const value = Number(code);
|
|
|
|
|
if (!Number.isFinite(value)) return 'bi-cloud';
|
|
|
|
|
if (value === 0) return 'bi-sun';
|
|
|
|
|
if (value <= 3) return 'bi-cloud-sun';
|
|
|
|
|
if (value <= 48) return 'bi-cloud-fog';
|
|
|
|
|
if (value <= 67) return 'bi-cloud-rain';
|
|
|
|
|
if (value <= 77) return 'bi-cloud-snow';
|
|
|
|
|
if (value <= 82) return 'bi-cloud-rain';
|
|
|
|
|
return 'bi-cloud-lightning-rain';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildWeatherPreview(location) {
|
|
|
|
|
const preview = {
|
|
|
|
|
hasSnapshot: false,
|
|
|
|
|
forecast: [{ day: 'Today', condition: '-', icon: 'bi-cloud', high: '-', low: '-', rain: '-' }, { day: 'Tomorrow', condition: '-', icon: 'bi-cloud', high: '-', low: '-', rain: '-' }, { day: 'Day 3', condition: '-', icon: 'bi-cloud', high: '-', low: '-', rain: '-' }, { day: 'Day 4', condition: '-', icon: 'bi-cloud', high: '-', low: '-', rain: '-' }, { day: 'Day 5', condition: '-', icon: 'bi-cloud', high: '-', low: '-', rain: '-' }, { day: 'Day 6', condition: '-', icon: 'bi-cloud', high: '-', low: '-', rain: '-' }, { day: 'Day 7', condition: '-', icon: 'bi-cloud', high: '-', low: '-', rain: '-' }],
|
|
|
|
|
hourly: Array.from({ length: 24 }, function () { return { day: '--:--', icon: 'bi-cloud', temperature: '-', rain: '-' }; }),
|
|
|
|
|
};
|
|
|
|
|
let snapshot;
|
|
|
|
|
try {
|
|
|
|
|
snapshot = JSON.parse(location && location.last_response_json || '');
|
|
|
|
|
} catch (_error) {
|
|
|
|
|
return preview;
|
|
|
|
|
}
|
|
|
|
|
if (!snapshot || typeof snapshot !== 'object') return preview;
|
|
|
|
|
const displaySnapshot = convertWeatherSnapshot(snapshot, { temperature: location.temperature_unit === 'fahrenheit' ? 'fahrenheit' : 'celsius', wind: location.wind_unit === 'mph' ? 'mph' : location.wind_unit === 'ms' ? 'ms' : 'kmh', precipitation: location.precipitation_unit === 'inch' ? 'inch' : 'mm' });
|
|
|
|
|
const current = displaySnapshot.current || {};
|
|
|
|
|
const daily = displaySnapshot.daily || {};
|
|
|
|
|
const hourly = displaySnapshot.hourly || {};
|
|
|
|
|
const weatherCode = Number(current.weather_code);
|
|
|
|
|
preview.hasSnapshot = true;
|
|
|
|
|
preview.location = location.location_label;
|
|
|
|
|
preview.temperatureUnit = location.temperature_unit === 'fahrenheit' ? '°F' : '°C';
|
|
|
|
|
preview.windUnit = location.wind_unit === 'mph' ? 'mph' : location.wind_unit === 'ms' ? 'm/s' : 'km/h';
|
|
|
|
|
preview.precipitationUnit = location.precipitation_unit === 'inch' ? 'in' : 'mm';
|
|
|
|
|
preview.temperature = current.temperature_2m ?? current.temperature ?? '-';
|
|
|
|
|
preview.feelsLike = current.apparent_temperature ?? current.feels_like ?? '-';
|
|
|
|
|
preview.icon = weatherIconForCode(weatherCode);
|
|
|
|
|
preview.condition = weatherCode === 0 ? 'Clear sky' : weatherCode <= 3 ? 'Partly cloudy' : weatherCode <= 48 ? 'Foggy' : weatherCode <= 67 ? 'Rain' : weatherCode <= 77 ? 'Snow' : weatherCode <= 82 ? 'Showers' : 'Thunderstorm';
|
|
|
|
|
preview.humidity = current.relative_humidity_2m === undefined ? '-' : current.relative_humidity_2m + '%';
|
|
|
|
|
preview.wind = current.wind_speed_10m ?? current.windSpeed ?? '-';
|
|
|
|
|
preview.precipitation = current.precipitation ?? '-';
|
|
|
|
|
preview.uvIndex = current.uv_index ?? '-';
|
|
|
|
|
preview.cloudCover = current.cloud_cover ?? '-';
|
|
|
|
|
preview.sunrise = daily.sunrise && daily.sunrise[0] ? String(daily.sunrise[0]).slice(11, 16) : '-';
|
|
|
|
|
preview.sunset = daily.sunset && daily.sunset[0] ? String(daily.sunset[0]).slice(11, 16) : '-';
|
|
|
|
|
preview.fetchedAt = location.last_pulled_at || '';
|
|
|
|
|
preview.forecast = (daily.time || []).slice(0, 7).map(function (day, index) {
|
|
|
|
|
const code = Number(daily.weather_code && daily.weather_code[index]);
|
|
|
|
|
return { day: index === 0 ? 'Today' : day, condition: code <= 3 ? 'Partly cloudy' : code <= 67 ? 'Rain' : code <= 77 ? 'Snow' : 'Showers', icon: weatherIconForCode(code), high: daily.temperature_2m_max && daily.temperature_2m_max[index] !== undefined ? daily.temperature_2m_max[index] : '-', low: daily.temperature_2m_min && daily.temperature_2m_min[index] !== undefined ? daily.temperature_2m_min[index] : '-', rain: daily.precipitation_sum && daily.precipitation_sum[index] !== undefined ? daily.precipitation_sum[index] : '-', wind: daily.wind_speed_10m_max && daily.wind_speed_10m_max[index] !== undefined ? daily.wind_speed_10m_max[index] : '-', uvIndex: daily.uv_index_max && daily.uv_index_max[index] !== undefined ? daily.uv_index_max[index] : '-' };
|
|
|
|
|
});
|
|
|
|
|
preview.hourly = (hourly.time || []).slice(0, 24).map(function (time, index) {
|
|
|
|
|
return { day: String(time).slice(11, 16), icon: weatherIconForCode(hourly.weather_code && hourly.weather_code[index]), temperature: hourly.temperature_2m && hourly.temperature_2m[index] !== undefined ? hourly.temperature_2m[index] : '-', rain: hourly.precipitation_probability && hourly.precipitation_probability[index] !== undefined ? hourly.precipitation_probability[index] + '%' : '-' };
|
|
|
|
|
});
|
|
|
|
|
return preview;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = function buildWeatherLocationFormViewModel(location, message, currentUser, isEdit, options) {
|
|
|
|
|
const weatherLocation = Object.assign(buildDefaultWeatherLocation(), location || {});
|
|
|
|
|
const providerAvailability = options && options.providerAvailability ? options.providerAvailability : { openMeteo: true, pirateWeather: false };
|
|
|
|
|
const formAction = isEdit ? '/data-sources/weather/' + weatherLocation.id : '/data-sources/weather';
|
|
|
|
|
return { title: isEdit ? 'Edit weather location' : 'Add weather location', active: 'weather', message, currentUser: currentUser || null, weatherLocation, weatherPreview: buildWeatherPreview(weatherLocation), providerAvailability, isEdit: Boolean(isEdit), formAction: formAction, formAttrs: isEdit ? 'data-async-save data-async-save-close-url="/data-sources/weather" data-async-save-new-url="/data-sources/weather/new"' : 'data-async-save data-async-save-new-redirect="response-url" data-async-save-close-url="/data-sources/weather" data-async-save-new-url="/data-sources/weather/new"', cancelUrl: '/data-sources/weather', deleteUrl: isEdit ? '/data-sources/weather/' + weatherLocation.id + '/delete' : '', deleteDisabled: !isEdit || Boolean(weatherLocation.inUse), showSaveSecondaryActions: true, scripts: ['js/data-sources/weather-location-form.js'] };
|
|
|
|
|
};
|