Skip to content

Commit 02eeef9

Browse files
committed
Initial UI for Hazard Info
1 parent 869e647 commit 02eeef9

8 files changed

Lines changed: 246 additions & 28 deletions

File tree

76.3 KB
Loading
14.2 KB
Loading

2wr-app/src/api/hazard-info-api.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ export default {
44
async getAll() {
55
return (await baseApiInstance.getInstance()).get('hazardinfo-list');
66
},
7+
8+
async get(id) {
9+
return (await baseApiInstance.getInstance()).get(`hazardinfo-by-id/${id}`);
10+
},
711
};

2wr-app/src/components/prepare/hazards/hazard-info-list.vue

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,25 @@
1010
indeterminate
1111
color="green"
1212
></v-progress-linear>
13-
<v-data-iterator v-if="!loading" :items="items" disable-pagination disable-sort hide-default-footer
14-
:search="search">
15-
<template v-slot:header>
16-
<v-text-field
17-
v-model="search"
18-
clearable
19-
label="Search"
20-
append-icon="mdi-magnify">
21-
</v-text-field>
22-
</template>
23-
<template v-slot:default="props">
24-
<div class="info-table">
25-
<v-card v-for="item in props.items" :key="item.id" class="my-4" ripple dark>
26-
<v-card-title class="white--text">
27-
<v-col class="col-9">
28-
<!-- <v-icon class="mr-2 white--text">{{item.icon}}</v-icon> -->{{ item.name }}
29-
</v-col>
30-
</v-card-title>
31-
<v-card-text>{{ item.description }}</v-card-text>
32-
</v-card>
33-
</div>
34-
</template>
35-
</v-data-iterator>
13+
<v-row dense>
14+
<v-col
15+
v-for="item in items"
16+
:key="item.id"
17+
cols="6"
18+
>
19+
<v-card
20+
@click="viewItem(item.id)">
21+
<v-img
22+
:src="item.iconUrl"
23+
class="white--text align-end"
24+
gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)"
25+
height="200px"
26+
>
27+
<v-card-title v-text="item.name"></v-card-title>
28+
</v-img>
29+
</v-card>
30+
</v-col>
31+
</v-row>
3632
</v-container>
3733
</template>
3834

@@ -56,6 +52,9 @@ export default {
5652
methods: {
5753
goBack() {
5854
window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/');
55+
},
56+
viewItem(id){
57+
this.$router.push(`/prepare/hazardinfo/${id}`);
5958
}
6059
}
6160
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<template>
2+
<v-container class="py-0">
3+
<v-app-bar app flat dense fixed color="background">
4+
<v-icon class="mr-2" v-on:click="goBack()">mdi-arrow-left</v-icon>
5+
<v-img :src="item.iconUrl" max-height="48" max-width="48" class="mr-2"></v-img>
6+
<v-toolbar-title>{{item ? item.name : 'Hazard Information'}}</v-toolbar-title>
7+
</v-app-bar>
8+
<v-row dense>
9+
<v-col cols="12">
10+
<p class="pa-2 headline">{{item.description}}</p>
11+
</v-col>
12+
<v-col cols="12">
13+
<v-img v-if="mediaUrlIsImage" :src="item.mediaUrl"></v-img>
14+
<!--TODO: Add option for videos once we have some sample videos -->
15+
</v-col>
16+
<v-col cols="12" class="text-center">
17+
<h2>{{item.name}} Safety</h2>
18+
</v-col>
19+
<v-col cols="12" class="text-center">
20+
<v-btn x-large color="primary" width="80%" @click="beforeDialog = true">Before</v-btn>
21+
</v-col>
22+
<v-col cols="12" class="text-center">
23+
<v-btn x-large color="primary" width="80%" @click="duringDialog = true">During</v-btn>
24+
</v-col>
25+
<v-col cols="12" class="text-center">
26+
<v-btn x-large color="primary" width="80%" @click="afterDialog = true">After</v-btn>
27+
</v-col>
28+
<v-col cols="12" class="text-center">
29+
<h2>{{item.name}} Resources</h2>
30+
</v-col>
31+
<v-col cols="12">
32+
<ul class="mb-6">
33+
<li v-for="link in item.externalLinks" :key={link} class="pa-1">
34+
<a :href="link" target="_blank">{{link}}</a><v-icon small class="ml-2">mdi-open-in-new</v-icon></li>
35+
</ul>
36+
</v-col>
37+
</v-row>
38+
<v-dialog
39+
v-model="beforeDialog"
40+
fullscreen
41+
hide-overlay
42+
transition="dialog-bottom-transition"
43+
scrollable
44+
>
45+
<v-card tile color="background">
46+
<v-toolbar class="flex-grow-0 mb-3"
47+
flat
48+
dark
49+
color="primary"
50+
>
51+
<v-btn
52+
icon
53+
dark
54+
@click="beforeDialog = false"
55+
>
56+
<v-icon>mdi-close</v-icon>
57+
</v-btn>
58+
<v-toolbar-title>{{item.name}} Safety: Before</v-toolbar-title>
59+
</v-toolbar>
60+
<v-card-text v-html="item.beforeSafetyDetails">
61+
</v-card-text>
62+
</v-card>
63+
</v-dialog>
64+
<v-dialog
65+
v-model="duringDialog"
66+
fullscreen
67+
hide-overlay
68+
transition="dialog-bottom-transition"
69+
scrollable
70+
>
71+
<v-card tile color="background">
72+
<v-toolbar class="flex-grow-0 mb-3"
73+
flat
74+
dark
75+
color="primary"
76+
>
77+
<v-btn
78+
icon
79+
dark
80+
@click="duringDialog = false"
81+
>
82+
<v-icon>mdi-close</v-icon>
83+
</v-btn>
84+
<v-toolbar-title>{{item.name}} Safety: During</v-toolbar-title>
85+
</v-toolbar>
86+
<v-card-text v-html="item.duringSafetyDetails">
87+
</v-card-text>
88+
</v-card>
89+
</v-dialog>
90+
<v-dialog
91+
v-model="afterDialog"
92+
fullscreen
93+
hide-overlay
94+
transition="dialog-bottom-transition"
95+
scrollable
96+
>
97+
<v-card tile color="background">
98+
<v-toolbar class="flex-grow-0 mb-3"
99+
flat
100+
dark
101+
color="primary"
102+
>
103+
<v-btn
104+
icon
105+
dark
106+
@click="afterDialog = false"
107+
>
108+
<v-icon>mdi-close</v-icon>
109+
</v-btn>
110+
<v-toolbar-title>{{item.name}} Safety: After</v-toolbar-title>
111+
</v-toolbar>
112+
<v-card-text v-html="item.afterSafetyDetails">
113+
</v-card-text>
114+
</v-card>
115+
</v-dialog>
116+
</v-container>
117+
</template>
118+
119+
<script>
120+
import { mapState } from 'vuex';
121+
122+
export default {
123+
data: () => {
124+
return {
125+
beforeDialog: false,
126+
duringDialog: false,
127+
afterDialog: false
128+
};
129+
},
130+
computed: {
131+
...mapState({
132+
item: (state) => state.hazardInfoStore.item,
133+
}),
134+
mediaUrlIsImage: function() {
135+
const mediaUrl = this.item?.mediaUrl?.toLowerCase();
136+
if (!mediaUrl) return false;
137+
138+
return mediaUrl.endsWith(".png") ||
139+
mediaUrl.endsWith(".jpg") ||
140+
mediaUrl.endsWith(".jpeg") ||
141+
mediaUrl.endsWith(".webp") ||
142+
mediaUrl.endsWith(".pjpeg") ||
143+
mediaUrl.endsWith(".svg") ||
144+
mediaUrl.endsWith(".pjp");
145+
}
146+
},
147+
mounted: function () {
148+
// Load the thing
149+
this.$store.dispatch(
150+
`hazardInfoStore/getHazardInfoAsync`,
151+
this.$route.params.id
152+
);
153+
},
154+
methods: {
155+
goBack() {
156+
window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/');
157+
}
158+
}
159+
}
160+
</script>
161+
162+
<style>
163+
164+
</style>

2wr-app/src/router/index.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import EmergencyKitCreatePage from '../views/prepare/emergency-kits/emergency-ki
77
import EmergencyKitEditPage from '../views/prepare/emergency-kits/emergency-kit-edit.vue';
88
import HazardHuntListing from '../views/prepare/hazards/hazard-hunt-list-view.vue';
99
import HazardInfoListing from '../views/prepare/hazards/hazard-info-list-view.vue';
10+
import HazardInfo from '../views/prepare/hazards/hazard-info-view.vue';
1011
import Recent from '../views/recent/recent.vue';
1112
import Settings from '../views/settings/settings.vue';
1213

@@ -60,13 +61,19 @@ const routes = [{
6061
}
6162
}, {
6263
path: '/prepare/hazardinfo',
63-
name: 'hazardinfo',
64+
name: 'hazardinfolist',
6465
component: HazardInfoListing,
6566
meta: {
6667
requiresAuth: true
6768
}
68-
},
69-
{
69+
}, {
70+
path: '/prepare/hazardinfo/:id',
71+
name: 'hazardinfodetails',
72+
component: HazardInfo,
73+
meta: {
74+
requiresAuth: true
75+
}
76+
}, {
7077
path: '/recent',
7178
name: 'recent',
7279
component: Recent

2wr-app/src/store/modules/prepare/hazards/hazard-info-store.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@ import localForage from 'localforage';
33

44
const CACHE_KEY = 'HazardInfos';
55
const SET_LIST = 'SET_LIST';
6+
const SET_ITEM = 'SET_ITEM';
67

78
export default {
89
namespaced: true,
910
state: {
10-
list: []
11+
list: [],
12+
item: null
1113
},
1214
mutations: {
1315
[SET_LIST](state, payload) {
1416
state.list = payload;
1517
},
18+
[SET_ITEM](state, payload) {
19+
state.item = payload;
20+
}
1621
},
1722
actions: {
1823
async getHazardInfosAsync({ commit, rootState }) {
@@ -35,7 +40,32 @@ export default {
3540
}
3641
}
3742
} catch {
38-
commit("setError", "Could not load harzard information.", { root: true });
43+
commit("setError", "Could not load hazard information.", { root: true });
44+
} finally {
45+
commit("clearBusy", null, { root: true });
46+
}
47+
},
48+
async getHazardInfoAsync({ commit, rootState} , id) {
49+
50+
try {
51+
commit("setBusy", null, { root: true });
52+
commit("setError", "", { root: true });
53+
const itemCacheKey = `${CACHE_KEY}/${id}`
54+
if (rootState.globalStore.online) {
55+
let response = await api.get(id);
56+
commit(SET_ITEM, response.data);
57+
await localForage.setItem(itemCacheKey, response.data);
58+
} else {
59+
var data = await localForage.getItem(itemCacheKey)
60+
if (data) {
61+
console.log("Serving from cache");
62+
commit(SET_ITEM, data);
63+
} else {
64+
console.log("Offline without data");
65+
}
66+
}
67+
} catch {
68+
commit("setError", "Could not load hazard information.", { root: true });
3969
} finally {
4070
commit("clearBusy", null, { root: true });
4171
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<HazardInformationComponent></HazardInformationComponent>
3+
</template>
4+
5+
<script>
6+
import HazardInformationComponent from '@/components/prepare/hazards/hazard-info.vue'
7+
8+
export default {
9+
name: 'HazardInfo',
10+
components: {
11+
HazardInformationComponent
12+
}
13+
}
14+
</script>

0 commit comments

Comments
 (0)