Add basic support for active weather alerts
yikes nobody should stake their life on how well this works, but it does seem to basically work..
This commit is contained in:
parent
7ed314b5bf
commit
0710f2238c
4 changed files with 134 additions and 2 deletions
|
@ -1,6 +1,7 @@
|
|||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomeView from '../views/HomeView.vue'
|
||||
import WeatherView from '../views/WeatherView.vue'
|
||||
import AlertsView from '../views/AlertsView.vue'
|
||||
import HourlyView from '../views/HourlyView.vue'
|
||||
import EditListView from '../views/EditListView.vue'
|
||||
|
||||
|
@ -17,6 +18,11 @@ const router = createRouter({
|
|||
name: 'weather',
|
||||
component: WeatherView,
|
||||
},
|
||||
{
|
||||
path: '/alerts',
|
||||
name: 'alerts',
|
||||
component: AlertsView,
|
||||
},
|
||||
{
|
||||
path: '/hourly',
|
||||
name: 'hourly',
|
||||
|
|
|
@ -10,6 +10,7 @@ const getDefaults = () => {
|
|||
coordinates,
|
||||
cityState,
|
||||
weather: null,
|
||||
alerts: null,
|
||||
forecast: null,
|
||||
radarLatestURL: null,
|
||||
radarLoopURL: null,
|
||||
|
@ -32,14 +33,17 @@ export const useWeatherStore = defineStore('weather', {
|
|||
this.setForecast(null)
|
||||
this.radarLatestURL = null
|
||||
this.radarLoopURL = null
|
||||
this.alerts = null
|
||||
},
|
||||
|
||||
async getWeather() {
|
||||
|
||||
if (!this.weather) {
|
||||
let url
|
||||
let response
|
||||
|
||||
const url = `https://api.weather.gov/points/${this.coordinates}`
|
||||
const response = await fetch(url)
|
||||
url = `https://api.weather.gov/points/${this.coordinates}`
|
||||
response = await fetch(url)
|
||||
const weather = await response.json()
|
||||
if (weather.status == 404) {
|
||||
throw new Error(`Data not found for ${this.coordinates}`)
|
||||
|
@ -57,6 +61,65 @@ export const useWeatherStore = defineStore('weather', {
|
|||
this.radarLoopURL = `https://radar.weather.gov/ridge/standard/${station}_loop.gif`
|
||||
|
||||
this.setWeather(weather)
|
||||
|
||||
// fetch zone to get its official id
|
||||
url = weather.properties.forecastZone
|
||||
response = await fetch(url)
|
||||
const zone = await response.json()
|
||||
|
||||
// fetch alerts for zone
|
||||
url = `https://api.weather.gov/alerts/active/zone/${zone.properties.id}`
|
||||
response = await fetch(url)
|
||||
const zoneAlerts = await response.json()
|
||||
|
||||
// fetch county to get its official id
|
||||
url = weather.properties.county
|
||||
response = await fetch(url)
|
||||
const county = await response.json()
|
||||
|
||||
// fetch alerts for county
|
||||
url = `https://api.weather.gov/alerts/active/zone/${county.properties.id}`
|
||||
response = await fetch(url)
|
||||
const countyAlerts = await response.json()
|
||||
|
||||
const newAlerts = {}
|
||||
|
||||
// use latest timestamp from either zone or county
|
||||
newAlerts.updated = zoneAlerts.updated
|
||||
if (countyAlerts.updated > zoneAlerts.updated) {
|
||||
newAlerts.updated = countyAlerts.updated
|
||||
}
|
||||
|
||||
// collect all alert "features" but de-duplicate them
|
||||
newAlerts.features = {}
|
||||
for (let feature of zoneAlerts.features) {
|
||||
newAlerts.features[feature.properties.id] = feature
|
||||
}
|
||||
for (let feature of countyAlerts.features) {
|
||||
newAlerts.features[feature.properties.id] = feature
|
||||
}
|
||||
newAlerts.features = Object.values(newAlerts.features)
|
||||
|
||||
// put "likely" before "possible" alerts
|
||||
newAlerts.features.sort((a, b) => {
|
||||
|
||||
if (a.properties.certainty == 'Likely' && b.properties.certainty == 'Possible') {
|
||||
return -1
|
||||
}
|
||||
if (a.properties.certainty == 'Possible' && b.properties.certainty == 'Likely') {
|
||||
return 1
|
||||
}
|
||||
|
||||
// if (a.properties.certainty == b.properties.certainty) {
|
||||
// return 0
|
||||
// }
|
||||
|
||||
// TODO: what else should this do?
|
||||
return 0
|
||||
})
|
||||
|
||||
// we have our final alerts
|
||||
this.alerts = newAlerts
|
||||
}
|
||||
|
||||
return this.weather
|
||||
|
|
51
src/views/AlertsView.vue
Normal file
51
src/views/AlertsView.vue
Normal file
|
@ -0,0 +1,51 @@
|
|||
<script setup>
|
||||
import { mapStores } from 'pinia'
|
||||
import { useWeatherStore } from '../stores/weather'
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
computed: {
|
||||
...mapStores(useWeatherStore),
|
||||
},
|
||||
|
||||
activated() {
|
||||
this.weatherStore.getWeather()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
|
||||
<o-button variant="primary"
|
||||
size="small"
|
||||
icon-left="arrow-left"
|
||||
@click="$router.push('/weather')">
|
||||
Back
|
||||
</o-button>
|
||||
|
||||
<h5 class="is-size-5">{{ weatherStore.cityState }}</h5>
|
||||
<h5 class="is-size-5">Alerts</h5>
|
||||
<br />
|
||||
|
||||
<o-collapse v-for="feature in weatherStore.alerts?.features || []"
|
||||
variant="warning"
|
||||
:open="false">
|
||||
<template #trigger>
|
||||
<o-notification :variant="feature.properties.certainty == 'Likely' ? 'danger' : 'warning'"
|
||||
icon="plus"
|
||||
icon-size="small"
|
||||
style="cursor: pointer;">
|
||||
{{ feature.properties.event }} ({{ feature.properties.severity }}, {{ feature.properties.certainty }})
|
||||
</o-notification>
|
||||
</template>
|
||||
<div class="notification">
|
||||
<h5 class="is-size-5 block">{{ feature.properties.headline }}</h5>
|
||||
<p class="block" style="white-space: pre-wrap;">{{ feature.properties.description }}</p>
|
||||
</div>
|
||||
</o-collapse>
|
||||
|
||||
</main>
|
||||
</template>
|
|
@ -10,6 +10,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
coordinates: null,
|
||||
alerts: null,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -48,6 +49,7 @@ export default {
|
|||
|
||||
const forecast = await this.weatherStore.getForecast()
|
||||
this.coordinates = this.weatherStore.coordinates
|
||||
this.alerts = this.weatherStore.alerts
|
||||
},
|
||||
|
||||
getShortForecast(period) {
|
||||
|
@ -77,6 +79,16 @@ export default {
|
|||
</o-select>
|
||||
</o-field>
|
||||
|
||||
<div v-if="alerts?.features?.length">
|
||||
<o-notification variant="warning"
|
||||
icon="warning"
|
||||
@click="$router.push('/alerts')"
|
||||
style="cursor: pointer;">
|
||||
<p class="has-text-weight-bold">Watches In Effect</p>
|
||||
<p>Updated {{ new Date(alerts.updated).toLocaleTimeString('en-US', {timeStyle: 'short'}) }}</p>
|
||||
</o-notification>
|
||||
</div>
|
||||
|
||||
<nav class="panel weather-panel">
|
||||
|
||||
<p class="panel-heading">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue