refactor(ui): use watchers to refresh display
[e-mobility-charging-stations-simulator.git] / ui / web / src / views / ChargingStationsView.vue
CommitLineData
32de5a57 1<template>
ca1e5439 2 <Container id="charging-stations-container">
239bd875
JB
3 <Container id="buttons-container">
4 <Container
5 v-show="Array.isArray(uiServerConfigurations) && uiServerConfigurations.length > 1"
6 id="ui-server-container"
0344ad2b 7 >
239bd875
JB
8 <select
9 id="ui-server-selector"
10 v-model="state.uiServerIndex"
11 @change="
12 () => {
13 if (
14 getFromLocalStorage<number>('uiServerConfigurationIndex', 0) !== state.uiServerIndex
15 ) {
7e315430 16 $uiClient.setConfiguration($configuration.value.uiServer[state.uiServerIndex])
aa9b0a1e 17 registerWSEventListeners()
7e315430 18 $uiClient.registerWSEventListener(
239bd875
JB
19 'open',
20 () => {
21 setToLocalStorage<number>('uiServerConfigurationIndex', state.uiServerIndex)
22 clearToggleButtons()
877b880c 23 $route.name !== 'charging-stations' &&
239bd875
JB
24 $router.push({ name: 'charging-stations' })
25 },
26 { once: true }
27 )
7e315430 28 $uiClient.registerWSEventListener(
239bd875
JB
29 'error',
30 () => {
31 state.uiServerIndex = getFromLocalStorage<number>(
32 'uiServerConfigurationIndex',
33 0
34 )
7e315430
JB
35 $uiClient.setConfiguration(
36 $configuration.value.uiServer[
239bd875
JB
37 getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
38 ]
39 )
aa9b0a1e 40 registerWSEventListeners()
239bd875
JB
41 },
42 { once: true }
43 )
44 }
45 }
46 "
0344ad2b 47 >
239bd875
JB
48 <option
49 v-for="uiServerConfiguration in uiServerConfigurations"
50 :value="uiServerConfiguration.index"
51 >
52 {{
53 uiServerConfiguration.configuration.name ?? uiServerConfiguration.configuration.host
54 }}
55 </option>
56 </select>
57 </Container>
240fa4da
JB
58 <ToggleButton
59 :id="'simulator'"
60 :key="state.renderSimulator"
f6cb1767 61 :status="simulatorState?.started"
240fa4da
JB
62 :on="() => startSimulator()"
63 :off="() => stopSimulator()"
ec7366ed 64 :class="simulatorButtonClass"
240fa4da 65 >
ec7366ed 66 {{ simulatorButtonMessage }}
240fa4da 67 </ToggleButton>
2610da71
JB
68 <ToggleButton
69 :id="'add-charging-stations'"
d64ea57b 70 :key="state.renderAddChargingStations"
2610da71
JB
71 :shared="true"
72 :on="
73 () => {
74 $router.push({ name: 'add-charging-stations' })
75 }
76 "
77 :off="
78 () => {
79 $router.push({ name: 'charging-stations' })
80 }
81 "
83468764
JB
82 @clicked="
83 () => {
84 state.renderChargingStations = randomUUID()
85 }
86 "
2610da71 87 >
1eb5f592 88 Add Charging Stations
2610da71 89 </ToggleButton>
b9d447d2
JB
90 <ReloadButton
91 id="reload-button"
26cf7d99
JB
92 :loading="state.gettingChargingStations"
93 @click="getChargingStations()"
b9d447d2 94 />
13c19b7b 95 </Container>
5c0e9352 96 <CSTable
7e315430 97 v-show="Array.isArray($chargingStations.value) && $chargingStations.value.length > 0"
3eea3ebc 98 :key="state.renderChargingStations"
7e315430 99 :charging-stations="$chargingStations.value"
83468764
JB
100 @need-refresh="
101 () => {
102 state.renderAddChargingStations = randomUUID()
103 state.renderChargingStations = randomUUID()
104 }
105 "
5c0e9352 106 />
32de5a57
LM
107 </Container>
108</template>
109
110<script setup lang="ts">
f6cb1767 111import { computed, getCurrentInstance, onMounted, onUnmounted, ref, watch } from 'vue'
cea23fa0 112import { useToast } from 'vue-toast-notification'
66a7748d 113import CSTable from '@/components/charging-stations/CSTable.vue'
e8237645 114import type { ResponsePayload, SimulatorState, UIServerConfigurationSection } from '@/types'
66a7748d
JB
115import Container from '@/components/Container.vue'
116import ReloadButton from '@/components/buttons/ReloadButton.vue'
2610da71 117import {
b767fda7 118 deleteFromLocalStorage,
2610da71
JB
119 getFromLocalStorage,
120 getLocalStorage,
121 randomUUID,
39cd8fcb
JB
122 setToLocalStorage,
123 useUIClient
2610da71
JB
124} from '@/composables'
125import ToggleButton from '@/components/buttons/ToggleButton.vue'
a4868fd7 126
f6cb1767
JB
127const simulatorState = ref<SimulatorState | undefined>(undefined)
128
129const simulatorButtonClass = computed<string>(() =>
130 simulatorState.value?.started === true ? 'simulator-stop-button' : 'simulator-start-button'
131)
132const simulatorButtonMessage = computed<string>(
133 () =>
134 `${simulatorState.value?.started === true ? 'Stop' : 'Start'} Simulator${simulatorState.value?.version != null ? ` (${simulatorState.value.version})` : ''}`
135)
136
240fa4da
JB
137const state = ref<{
138 renderSimulator: `${string}-${string}-${string}-${string}-${string}`
139 renderAddChargingStations: `${string}-${string}-${string}-${string}-${string}`
140 renderChargingStations: `${string}-${string}-${string}-${string}-${string}`
26cf7d99
JB
141 gettingSimulatorState: boolean
142 gettingTemplates: boolean
143 gettingChargingStations: boolean
240fa4da
JB
144 uiServerIndex: number
145}>({
146 renderSimulator: randomUUID(),
147 renderAddChargingStations: randomUUID(),
148 renderChargingStations: randomUUID(),
26cf7d99
JB
149 gettingSimulatorState: false,
150 gettingTemplates: false,
151 gettingChargingStations: false,
240fa4da
JB
152 uiServerIndex: getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
153})
154
d64ea57b
JB
155const clearToggleButtons = (): void => {
156 for (const key in getLocalStorage()) {
157 if (key.includes('toggle-button')) {
b767fda7 158 deleteFromLocalStorage(key)
d64ea57b
JB
159 }
160 }
26cf7d99
JB
161 state.value.renderChargingStations = randomUUID()
162 state.value.renderAddChargingStations = randomUUID()
d64ea57b
JB
163}
164
97cd0ef3
JB
165const app = getCurrentInstance()
166
f6cb1767
JB
167watch(app?.appContext.config.globalProperties.$chargingStations, () => {
168 state.value.renderChargingStations = randomUUID()
169})
170
171watch(simulatorState, () => {
172 state.value.renderSimulator = randomUUID()
173})
174
175const clearTemplates = (): void => {
176 if (app != null) {
177 app.appContext.config.globalProperties.$templates.value = []
178 }
179}
180
d64ea57b 181const clearChargingStations = (): void => {
26cf7d99 182 if (app != null) {
7e315430 183 app.appContext.config.globalProperties.$chargingStations.value = []
26cf7d99 184 }
d64ea57b
JB
185}
186
39cd8fcb 187const uiClient = useUIClient()
240fa4da 188
97cd0ef3
JB
189const $toast = useToast()
190
240fa4da 191const getSimulatorState = (): void => {
26cf7d99
JB
192 if (state.value.gettingSimulatorState === false) {
193 state.value.gettingSimulatorState = true
3b0c6e17 194 uiClient
26cf7d99 195 .simulatorState()
3b0c6e17 196 .then((response: ResponsePayload) => {
f6cb1767 197 simulatorState.value = response.state as SimulatorState
3b0c6e17
JB
198 })
199 .catch((error: Error) => {
26cf7d99
JB
200 $toast.error('Error at fetching simulator state')
201 console.error('Error at fetching simulator state:', error)
3b0c6e17 202 })
240fa4da 203 .finally(() => {
26cf7d99 204 state.value.gettingSimulatorState = false
240fa4da 205 })
26cf7d99
JB
206 }
207}
208
97cd0ef3
JB
209const getTemplates = (): void => {
210 if (state.value.gettingTemplates === false) {
211 state.value.gettingTemplates = true
212 uiClient
213 .listTemplates()
214 .then((response: ResponsePayload) => {
215 if (app != null) {
7e315430 216 app.appContext.config.globalProperties.$templates.value = response.templates
97cd0ef3
JB
217 }
218 })
219 .catch((error: Error) => {
f6cb1767 220 clearTemplates()
97cd0ef3
JB
221 $toast.error('Error at fetching charging station templates')
222 console.error('Error at fetching charging station templates:', error)
223 })
224 .finally(() => {
225 state.value.gettingTemplates = false
226 })
227 }
916fe456
JB
228}
229
26cf7d99
JB
230const getChargingStations = (): void => {
231 if (state.value.gettingChargingStations === false) {
232 state.value.gettingChargingStations = true
57c0ba05
JB
233 uiClient
234 .listChargingStations()
235 .then((response: ResponsePayload) => {
236 if (app != null) {
7e315430 237 app.appContext.config.globalProperties.$chargingStations.value = response.chargingStations
57c0ba05
JB
238 }
239 })
240 .catch((error: Error) => {
f6cb1767 241 clearChargingStations()
cea23fa0 242 $toast.error('Error at fetching charging stations')
57c0ba05
JB
243 console.error('Error at fetching charging stations:', error)
244 })
245 .finally(() => {
26cf7d99 246 state.value.gettingChargingStations = false
57c0ba05 247 })
2113b3c6 248 }
32de5a57 249}
5a010bf0 250
aa9b0a1e
JB
251const getData = (): void => {
252 getSimulatorState()
253 getTemplates()
254 getChargingStations()
255}
256
257const registerWSEventListeners = () => {
258 uiClient.registerWSEventListener('open', getData)
97cd0ef3
JB
259 uiClient.registerWSEventListener('error', clearChargingStations)
260 uiClient.registerWSEventListener('close', clearChargingStations)
261}
262
aa9b0a1e
JB
263const unregisterWSEventListeners = () => {
264 uiClient.unregisterWSEventListener('open', getData)
265 uiClient.unregisterWSEventListener('error', clearChargingStations)
266 uiClient.unregisterWSEventListener('close', clearChargingStations)
267}
268
97cd0ef3 269onMounted(() => {
aa9b0a1e
JB
270 registerWSEventListeners()
271})
272
273onUnmounted(() => {
274 unregisterWSEventListeners()
97cd0ef3
JB
275})
276
277const uiServerConfigurations: { index: number; configuration: UIServerConfigurationSection }[] =
7e315430 278 app?.appContext.config.globalProperties.$configuration.value.uiServer.map(
97cd0ef3
JB
279 (configuration: UIServerConfigurationSection, index: number) => ({
280 index,
281 configuration
282 })
283 )
284
fa5d129a 285const startSimulator = (): void => {
cea23fa0
JB
286 uiClient
287 .startSimulator()
288 .then(() => {
289 $toast.success('Simulator successfully started')
290 })
291 .catch((error: Error) => {
292 $toast.error('Error at starting simulator')
293 console.error('Error at starting simulator:', error)
294 })
240fa4da
JB
295 .finally(() => {
296 getSimulatorState()
297 })
5a010bf0 298}
fa5d129a 299const stopSimulator = (): void => {
cea23fa0
JB
300 uiClient
301 .stopSimulator()
302 .then(() => {
f6cb1767 303 clearChargingStations()
cea23fa0
JB
304 $toast.success('Simulator successfully stopped')
305 })
306 .catch((error: Error) => {
307 $toast.error('Error at stopping simulator')
308 console.error('Error at stopping simulator:', error)
309 })
240fa4da
JB
310 .finally(() => {
311 getSimulatorState()
312 })
5a010bf0 313}
32de5a57
LM
314</script>
315
316<style>
ca1e5439 317#charging-stations-container {
1d41bc6b 318 height: fit-content;
32de5a57 319 width: 100%;
5a010bf0 320 display: flex;
32de5a57 321 flex-direction: column;
5a010bf0
JB
322}
323
0344ad2b
JB
324#ui-server-container {
325 display: flex;
239bd875 326 justify-content: center;
754d8199 327 border-style: outset;
0344ad2b
JB
328}
329
330#ui-server-selector {
331 width: 100%;
239bd875 332 background-color: rgb(239, 239, 239);
c6308554 333 font: small-caption;
0344ad2b
JB
334 text-align: center;
335}
336
239bd875 337#ui-server-selector:hover {
bad93db3 338 background-color: rgb(229, 229, 229);
239bd875
JB
339}
340
13c19b7b
JB
341#buttons-container {
342 display: flex;
343 flex-direction: row;
344}
345
6027002f 346.simulator-start-button {
3802683b
JB
347 color: ivory;
348 background-color: green;
349}
350
fec03138 351.simulator-start-button:hover {
fec03138
JB
352 background-color: rgb(0, 98, 0);
353}
354
6027002f 355.simulator-stop-button {
3802683b
JB
356 color: ivory;
357 background-color: red;
358}
359
fec03138
JB
360.simulator-stop-button:hover {
361 background-color: rgb(225, 0, 0);
362}
363
14ee627a
JB
364#action-button {
365 flex: none;
878855a2
JB
366}
367
32de5a57 368#reload-button {
3802683b 369 color: ivory;
9dc8b66f 370 background-color: blue;
c6308554 371 font-size: 2rem;
32de5a57
LM
372}
373
374#reload-button:hover {
9dc8b66f 375 background-color: rgb(0, 0, 225);
32de5a57
LM
376}
377
378#reload-button:active {
4b10e4f9 379 background-color: darkblue;
32de5a57 380}
229d8c34
JB
381
382#action {
916f0920 383 min-width: max-content;
3802683b 384 color: ivory;
229d8c34 385 background-color: black;
916f0920 386 padding: 0.8%;
229d8c34 387}
32de5a57 388</style>